动态规划训练25 [Food Delivery ZOJ

来源:互联网 发布:windows怎么开ssh 编辑:程序博客网 时间:2024/06/05 20:47

Food Delivery

 ZOJ - 3469 

区间DP的一道好题。

在这道题里,无非就是从出发点向左走到x1再向右走到有y1,再向左走到x2,再向右走到y2.。。。这样,一直将所有的顾客遍历完。

显然,起点这个点是非常特殊的一个点,我们姑且也把它算作一名顾客,那么这名顾客的愤怒值设置为0。

然后定义dp[x][y][0]表示区间遍历完[x,y]了,并且当前停留在x位置上,将对最终的愤怒值之和造成的贡献。

定义dp[x][y][1]表示遍历完区间[x,y],并且当前停留在y位置上,将对最终的愤怒之和造成的贡献。

从上面我们的讨论中可以发现[x,y]一定是包含起始点S的,不然这个区间将没有意义。

我们可以得到状态转移的方程 (我们没有在这里就把V乘进去,而是在最后才把V考虑进去)

dp[i][j][0] = min(dp[i][j][0],dp[i+1][j][0] + (Ns[i+1].x - Ns[i].x)*(sum[N+1] - (sum[j] - sum[i])));
dp[i][j][0] = min(dp[i][j][0],dp[i+1][j][1] + (Ns[j].x - Ns[i].x)*(sum[N+1] - (sum[j] - sum[i])));
dp[i][j][1] = min(dp[i][j][1],dp[i][j-1][1] + (Ns[j].x - Ns[j-1].x)*(sum[N+1] - (sum[j-1] - sum[i-1])));
dp[i][j][1] = min(dp[i][j][1],dp[i][j-1][0] + (Ns[j].x - Ns[i].x)*(sum[N+1] - (sum[j-1] - sum[i-1])));

以上的状态转移方程就相当于把区间扩大了一位数字,贡献增加的值。

我看很多题解的时候,没有明确说明dp表示的是对于答案的贡献值,所以没能充分的理解。

反思这个动态规划的题目,有点特别,就是说dp代表的东西不能形成一个类似的独立的子问题,而仍然是刻画原问题的某个性质的一部分,这里我觉得是与其他一些dp不同的地方。


#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>using namespace std;int N,V,X; const int INF = 1e9;const int MAX = 1005;struct node{int x,val;friend bool operator<(node n1,node n2){return n1.x < n2.x;}}Ns[MAX];int dp[MAX][MAX][2];int sum[MAX];int main(){while(~scanf("%d%d%d",&N,&V,&X)){memset(dp,0,sizeof(dp));for(int i = 1;i <= N;i++){int x,b;scanf("%d%d",&x,&b);Ns[i].x = x;Ns[i].val = b;}Ns[N+1].x = X;Ns[N+1].val = 0;sort(Ns+1,Ns+N+2);int s = 0;while(Ns[++s].x != X);for(int i = 1;i <= N+1;i++) sum[i] = sum[i-1] + Ns[i].val;for(int i = 1;i <= N+1;i++){for(int j = 1;j <= N+1;j++){dp[i][j][0] = dp[i][j][1] = INF;}}dp[s][s][0] = dp[s][s][1] = 0;for(int i = s;i > 0;i--){for(int j = s;j<= N+1;j++){if(i == j) continue;dp[i][j][0] = min(dp[i][j][0],dp[i+1][j][0] + (Ns[i+1].x - Ns[i].x)*(sum[N+1] - (sum[j] - sum[i])));dp[i][j][0] = min(dp[i][j][0],dp[i+1][j][1] + (Ns[j].x - Ns[i].x)*(sum[N+1] - (sum[j] - sum[i])));dp[i][j][1] = min(dp[i][j][1],dp[i][j-1][1] + (Ns[j].x - Ns[j-1].x)*(sum[N+1] - (sum[j-1] - sum[i-1])));dp[i][j][1] = min(dp[i][j][1],dp[i][j-1][0] + (Ns[j].x - Ns[i].x)*(sum[N+1] - (sum[j-1] - sum[i-1])));}}int ans = min(dp[1][N+1][0],dp[1][N+1][1]);printf("%d\n",ans*V);}return 0;} 


原创粉丝点击