题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3466
题目理解:
有n(2 <= n <= 50)个车站,从左到右编号1-n, m1(1 <= m1 <= 50)辆车从1往右开, m2(1 <= m2 <= 50)辆车从n往左开。Mario时刻0从1出发,打算在T(0 <= T <= 200)时刻在n与人会面。在车站等车容易被抓,所以她尽量躲在火车上,让在车站等车的总时间尽量短。求在车站等车的最短时间
输入:
多组数据, 第一行n,第二行T,第三行n - 1个数t [1] - t [n - 1] (1 <= t <= 70)表示从第i个车站开到i + 1车站需要的时间(两个方向相同),第四行m1,第五行m1个整数表示各列车从1站的出发时间(0 <= d[i] <= 250) d[i] < d[i + 1]。第六行m2, 第七行各列车从n站出发的时间。不能到测输出impossible。
算法竞赛入门经典例题9-1
学dp总是感觉很迷茫,不知从何学起,还好难理解.... 多看,多理解,多想。
书上说,在每个车站有三种决策:
1、等一个时刻
2、乘往右开的列车(有的话)
3、乘往左开的列车(有的话)
程序中dp[ i ][ j ]表示时刻 i,在车站 j 到达目的要求需花费的最少时间。显然边界条件是dp[ T ][ n ] = 0。
方便起见,先打表has_train[ i ] [ j ] [ 0 ] 表示 i 时刻 在 j 车站有无向右开的车,has_train[ i ] [ j ] [ 1 ] 表示 i 时刻 在 j 车站有无向左开的车,打表的过程有一些小细节需要注意,祥见代码。 状态方程为dp[ i ][ j ] = min( dp[ i + 1][ j ] + 1, dp[ i + t[ j ]] [ j + 1 ], dp[i + t[j - 1]] [ j - 1] ) ,当然,后面两个是有车存在的情况下。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std; const int inf = 0x3f3f3f3f; int main() { int n, T, m1, m2, kase = 0; int t[55]; int has_train[210][55][2]; int dp[210][55]; while(~scanf("%d", &n) && n) { scanf("%d", &T); int i, j; for(i = 1; i <= n - 1; i++) { scanf("%d", &t[i]); } memset(has_train, 0, sizeof(has_train)); scanf("%d", &m1); int tmp; for(i = 1; i <= m1; i++) { //打表记录有无向右开的车 scanf("%d", &tmp); for(j = 1; j <= n - 1; j++) { //只需记录到 n - 1站,因为到了n站绝不会再往右开了 if(tmp < T) has_train[tmp][j][0] = 1; // tmp == T的时候可看作无车,因为已经到时间了 tmp += t[j]; //开到下一站的时间 } } scanf("%d", &m2); for(i = 1; i <= m2; i++) { //打表记录有无向左开的车 scanf("%d", &tmp); for(j = n; j >= 2; j--) { if(tmp < T) has_train[tmp][j][1] = 1; tmp += t[j - 1]; //t[j - 1]也表示从 j 车站开到 j - 1车站的时间 } } for(i = 1; i <= n - 1; i++) dp[T][i] = inf; // 这些情况都是不可能到达的情况 dp[T][n] = 0; //边界情况 for(i = T - 1; i >= 0; i--) { //从后往前递推 for(j = 1; j <= n; j++) { dp[i][j] = dp[i + 1][j] + 1; //决策一 if(j < n && has_train[i][j][0] && i + t[j] <= T) dp[i][j] = min(dp[i][j], dp[i + t[j]][j + 1]); //决策二 ,上向右的车 if(j > 1 && has_train[i][j][1] && i + t[j - 1] <= T) dp[i][j] = min(dp[i][j], dp[i + t[j - 1]][j - 1]); //决策三 ,上向左的车 } } printf("Case Number %d: ", ++kase); if(dp[0][1] >= inf) printf("impossible\n"); else printf("%d\n", dp[0][1]); } return 0; }