这道题是紫书里的,以下的主代码也来自紫书,但笔者会在这里做一些补充说明。
本题中把单向流逝的时间作为拓补序,用时刻和位置作为状态参数,
dp【i】【j】表示在i车站,j时刻时还需等待的最少时间(其实通常我们把表示阶段的放在前面)
边界是这个:
dp[n][tm]=0;
for(int i=1;i<n;i++)
dp[i][tm]=inf;//时间到了,人却不在车站,任务失败
主代码如下
for(int j=tm-1;j>=0;j--)
for(int i=1;i<=n;i++)
{
dp[i][j]=dp[i][j+1]+1;
if(has_train[i][j][0]&&i<n&&j+t[i]<=tm)
dp[i][j]=min(dp[i][j],dp[i+1][j+t[i]]);
if(has_train[i][j][1]&&i>1&&j+t[i-1]<=tm)
dp[i][j]=min(dp[i][j],dp[i-1][j+t[i-1]]);
}
第二行其实是可以改成 for(int i=n;i>=1;i--)的,因为
dp[j+1][ ]的情况都已经打出来了,外循环和内循环的位置不可交换,因为我们的拓补序是时间(逆流的);
关于has_train[ ][ ][ ]我的打法是这样的,过了uva的评测,但是效率较低
cin>>m1;
for(int i=1;i<=m1;i++) //T(0≤T≤200) 0 ≤ di ≤ 250
{
cin>>tmp;
has_train[1][tmp][0]=1;
}
cin>>m2;
for(int i=1;i<=m2;i++)
{
cin>>tmp;
has_train[n][tmp][1]=1;
}
for(int i=2;i<=n;i++)
for(int j=t[i-1];j<=tm;j++)
{
has_train[i][j][0]=has_train[i-1][j-t[i-1]][0]==1?1:0;
}
这是一种很盲的递推,洛谷的题解里有一篇更好的办法:
for(int i=1; i<=M1; i++){
int t1;//左站出发时间
cin>>t1;
int sum=t1;
for(int j=1; j<=n; j++){
trainl[j][sum] = 1;
sum+=t[j];
}
}//谢谢alecli大佬
题解到此结束