实际上这题就是问Mario最少的总等车时间
这题我的做法是
把一个火车从左到右(或从右到左) 的过程
转化成
途中任何车站到左边(或右边)相邻车站 的过程
相当于把他切成了一段一段
(一段就是两个相邻车站中间的部分)
这样更容易操作
具体请看代码
一些注释在代码里请往下看
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int Time = 205, N = 55;
bool has_train[20 * N][N][2];
int dp[Time][N], t[N];
int main() {
int n, T, Case;
Case = 0;
while (scanf ("%d", &n), n) {
memset(t, 0, sizeof t);
memset(has_train, false, sizeof has_train);
scanf ("%d", &T);
int tmp = 0;
//t[i] : 从第i个车站 ~ 第i+1个车站 耗费的时间 (反向也是)
for (int i = 1; i < n; i ++)
scanf ("%d", &t[i]);
int ml, mr;
//ml 是从第一站向右开的火车的发班时间
scanf ("%d", &ml);
//下面两个while是用来编写has_train的 具体has_train的意义下面会讲
while (ml --) {
int di;
scanf ("%d", &di); //发班时间
int time = di;
for (int k = 1; k <= n; k ++)
has_train[time += t[k - 1]][k][0] = true; //向右
}
//mr 是从最后一站向左开的火车的发班时间
scanf ("%d", &mr);
while (mr --) {
int di;
scanf ("%d", &di); //发班时间
int time = di;
for (int k = n; k >= 1; k --)
has_train[time += t[k]][k][1] = true; //向左
}
/*
dp(i,j) 第i个时刻在第j个车站 最少等的总时间
三种情况:
1). 等一分钟
dp(i,j) = dp(i+1,j) + 1;
2). 坐往右开的车(如果有)
dp(i,j) = dp(i+t[j],j+1)
3). 坐往左开的车(如果有)
dp(i,j) = dp(i+t[j-1],j-1)
三个状态去一个min
所有初始化成一个0x7f7f7f7f (及无解)
dp(T,n)=0;
has[i][j][sign] : 第i个时刻第j个车站是否有向右(sign == 0)或左(sign == 1)的车
*/
for (int i = 1; i < n; i ++)
dp[T][i] = 0x7f7f7f7f;
dp[T][n] = 0;
for (int i = T - 1; i >= 0; i --) {
for (int 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]);
}
}
int ans = dp[0][1];
printf ("Case Number %d: ", ++ Case);
if (ans < 0x7f7f7f7f)
printf ("%d\n", ans);
else
printf ("impossible\n");
}
return 0;
}
题目传送门:UVA1025 城市里的间谍
制作不易,留个赞再走吧