UVa 1025
开始系统跟着刘汝佳老师的书并行刷题。
DP问题似乎很多问题是会将时间这类有序的量作为状态一个坐标,这个思路还是蛮惊奇的,建立在题目中时间是整数,并且数量级可以接受的情况。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
const int maxn= 55;
const int maxt= 205;
const int INF= 0x3f3f3f3f;
int tt[maxn], ls[maxn], rs[maxn];
int has_train[maxt][maxn][2];
int dp[maxt][maxn];
void Init(int t, int n)
{
memset(dp, 0x3f, sizeof(dp));
memset(tt, 0, sizeof(tt));
memset(ls, 0, sizeof(ls));
memset(rs, 0, sizeof(rs));
memset(has_train, 0, sizeof(has_train));
dp[t][n]= 0;
}
void SetHasTrain(int t, int n, int m1, int m2)
{
int b= 0;
for (int i= 1; i<= n-1; ++i){
b+= tt[i-1];
for (int d= 0; d< m1; ++d){
if (b+ls[d]<= t){
has_train[b+ls[d]][i][0]= 1;
}
}
}
b= 0;
for (int i= n; i> 1; --i){
b+= tt[i];
for (int d= 0; d< m2; ++d){
if (b+rs[d]<= t){
has_train[b+rs[d]][i][1]= 1;
}
}
}
}
int main(int argc, char const *argv[])
{
int n, t, m1, m2;
int kase= 0;
while (1){
scanf("%d", &n);
if (0== n){
break;
}
scanf("%d", &t);
Init(t, n);
for (int i= 1; i< n; ++i){
scanf("%d", tt+i);
}
scanf("%d", &m1);
for (int i= 0; i< m1; ++i){
scanf("%d", ls+i);
}
scanf("%d", &m2);
for (int i= 0; i< m2; ++i){
scanf("%d", rs+i);
}
SetHasTrain(t, n, m1, m2);
for (int i= t-1; i>= 0; --i){
for (int j= n; j> 0; --j){
int x= dp[i+1][j]+1;
//left
if (j> 1 && has_train[i][j][1] && i+tt[j-1]<= t){
x= min(x, dp[i+tt[j-1]][j-1]);
}
// right
if (j< n && has_train[i][j][0] && i+tt[j]<= t){
x= min(x, dp[i+tt[j]][j+1]);
}
dp[i][j]= x;
}
}
cout<<"Case Number "<<++kase<<": ";
if (dp[0][1]>= INF){
cout<<"impossible"<<endl;
}
else{
cout<<dp[0][1]<<endl;
}
}
return 0;
}