UVa1025 (DAG上的dp)
Posted 温和的提比略
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa1025 (DAG上的dp)相关的知识,希望对你有一定的参考价值。
这是紫书上的第一个dp哈。
1.状态定义:dp[i][j]---->到时刻i的时候(出发的时候时刻为0,约定时间为时刻time),从j号车站开往N号车站,在车站等待的最少的时间。
2.这个人当前的策略:
α.在车站等待一个单位的时间(该站此时没有发车时应该这么做)
β.坐上开往左边的火车
γ.坐上开往右边的火车
3.状态转移方程:dp[i][j] = min(dp[i+1][j]+1,dp[i+t[j]][j+1],dp[i+t[j-1]][j-1])
我们可以做一个乘车时刻表来记录i时刻j车站是否有车经过。
dp[time][N] = 0,其余初始化为正无穷。
同时,可以看出,时刻i一直在往大的方向转移,所以,i的循环应该是逆序。
还有,按道理来说这个人不一定只在该车站仅仅等待1个单位时间,应该可以等待k个,然而在更新dp[i+1][j]时(由于是逆序循环,所以dp[i+1][j]先被考虑)也考虑了等待的问题,所以只需要考虑当前时刻的这1单位时刻等待与否,之前的k-1个单位时刻其实已经考虑过了。
贴AC代码:
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #define maxn1 55 #define maxn2 255 #define F 0x3f #define INF 0x3f3f3f3f using namespace std; int timetable[2][maxn2][maxn1]; int t[maxn1],dp[maxn2][maxn1]; int main() { int N,cas = 1; while(scanf("%d",&N) == 1 && N){ int time; scanf("%d",&time); for(int i = 1;i < N;++i) scanf("%d",&t[i]); memset(timetable,0,sizeof(timetable)); memset(dp,F,sizeof(dp)); int M1,M2,train; scanf("%d",&M1); for(int i = 0;i < M1;++i){ scanf("%d",&train); int sum = train; for(int j = 1,k = 1;j < N && k <= N;sum += t[j],++j,++k){ if(sum > time) break; timetable[0][sum][k] = 1; } } scanf("%d",&M2); for(int i = 0;i < M2;++i){ scanf("%d",&train); int sum = train; for(int j = N - 1,k = N;j >= 1 && k >= 1;sum += t[j],--j,--k){ if(sum > time) break; timetable[1][sum][k] = 1; } } dp[time][N] = 0; for(int i = time - 1;i >= 0;--i){ for(int j = 1;j <= N;++j){ dp[i][j] = dp[i + 1][j] + 1; if(timetable[0][i][j] && j < N && i + t[j] <= time) dp[i][j] = min(dp[i][j],dp[i + t[j]][j + 1]); if(timetable[1][i][j] && j > 1 && i + t[j - 1] <= time) dp[i][j] = min(dp[i][j],dp[i + t[j - 1]][j - 1]); } } if(dp[0][1] >= INF) printf("Case Number %d: impossible\n",cas++); else printf("Case Number %d: %d\n",cas++,dp[0][1]); } return 0; }
以上是关于UVa1025 (DAG上的dp)的主要内容,如果未能解决你的问题,请参考以下文章
UVA 1025 A Spy in the Metro DAG上DP/逆推/三维标记数组+二维状态数组
UVA - 10131Is Bigger Smarter?(DAG上的DP)