Road or Flight——ACM簡單DP

NEUOJ 1052——Road or Flight(Easy DP)
一,原題及數據
Problem 1052 - Road or Flight
Time Limit:1000MS  Memory Limit:65536KB
Total Submit:144  Accepted:25
Description
The king has been out to work for a long time and he wants to go back to his queen as fast as possible. The king is in city 0 and the queen is in city N. There are roads and flights connecting city i to city (i+1) for all i between 0 and N-1, inclusive.  Hence the queen has asked the king to take at most K flights on his way.  Your should tell the king the minimum amount of time in which the king can reach his queen.
Input
There are several test case, for each case:
First line, contains two integers N,K(0 <= K &lt;= N &lt;= 50) as the Describe.
Follow N lines, each line contains two integers roadtime,flighttime (0 &lt;= roadtime,flighttime &lt;= 1000) representing the time it takes to travel from city i to city (i+1) by road and by flight respectively.
Output
For each test case, you just output minimum amount of time in which the king can reach his queen.
Sample Input
3 1
4 1
6 2
7 3
7 2
50 797
287 661
621 644
266 102
224 114
68 452
636 420
Sample Output
13
1772
二,思路及示例分析
這個題,一上來第一反應就寫了一個dfs。抱着僥倖的心理交了一次,很明顯的WA了。
int dfs(int v,int m)//dfs
{
   if(v==n-1)//reach
   {
   if(m>=k)return r[v];
   return min(r[v],f[v]);
   }
   if(m&gt;=k)//over k
   return road(v);
   return min(r[v]+dfs(v+1,m),f[v]+dfs(v+1,m+1));
}
不過這個dfs確實頗有意義的。這個dfs給了我不少的啓發。先解釋一下這個算法的思路。
令r[i],f[i]表示i,i+1之間的費用。
Dfs(v,m)表示到已經乘坐了m次飛機,從v到終點的最小費用。
遞歸的過程爲:
若是v就是終點
若是m&gt;=k,既是坐飛機的次數超過了限制,則返回r[v]。
不然,返回r[v],f[v]的較小值。
若是m&gt;=k,
返回從m到終點選擇road方式的總費用。
返回在v點是選擇兩種不一樣方式的最小值。若是選擇road,則m依然不變,費用能夠表示爲r[v]+dfs(v+1,m),即當前的費用加上從v+1到終點的費用,飛行次數已經使用了m次。
若是不選擇road,則m+1,費用能夠表示爲f[v]+dfs(v+1,m+1),即當前的費用加上從v+1到終點的費用,飛行次數已經使用了m+1次。
不過這個算法無疑是TLE。可是容易理解,我當即將他改爲了DP的形式。令數組dp[i][j]表示已經乘坐了j次飛機,從i到終點的最小費用。則原題的解爲dp[0][0]。問題轉化爲求dp[0][0]。
其中狀態轉移方程爲:
Dp[i][j]= wps_clip_p_w_picpath-14643
這樣能夠用一個二重循環就能夠解決了。
三,程序代碼
#include<stdio.h>
const int N=51;
int r[N];//r[i] biaoshi i--&gt;i+1
int f[N];
int n,k;
int dp[N][N];//record
int min(int a,int b)
{
return a<b?a:b;
}
int road(int v)
{
  int i=v,sum=0;
  for(;i&lt;n;i++)
     sum+=r[i];
  return sum;
}
//dp return a[0][0]
void dfstodp()
{
  int i,j;
  for(i=n-1,j=0;j&lt;k;j++)
  {
dp[i][j]=min(r[i],f[i]);
  }//init d[n-1] from d[n-1][0] to d[n-1][k-1];
  for(j=k,i=n-1;i>=0;i--)
  {
  dp[i][j]=road(i);
  }//init d[][k] from d[n-1][k] to d[0][k];
  for(i=n-2;i&gt;=0;i--)
  for(j=k-1;j&gt;=0;j--)
dp[i][j]=min(r[i]+dp[i+1][j],f[i]+dp[i+1][j+1]); 
}
int main()
{
   int i=0;
   int sum=0;
   while(scanf("%d%d",&n,&k)!=EOF)
   {
   for(i=0;i&lt;n;i++)
   scanf("%d%d",&r[i],&f[i]);
   dfstodp();
   printf("%d\n",dp[0][0]);
   }
   return 0;
}
四,總結
1,DP的難點在於構造狀態轉移方程。簡單的不帶狀態回退的DFS應該都能用DP來實現吧。
2,能用非遞歸算法的,最好不要用遞歸算法。除非時空都相同,深度也差很少。
相關文章
相關標籤/搜索