看dp真的是能挫败自信心,感觉智商高低就能在这里体现了…
感觉真的不太会用dp啊,尤其是递推式,不会写呢~~(感觉是自己太弱了)~~
然后这题也是看的紫书先,还是有点懵,看网上大神的题解,感觉跟紫书差不多。
但是我自己还是不是很理解啊,反复啃了好久终于是理解了。
dp[i][j] 代表的是 现在在i时刻 j站 还需要等待多久时间..
起点 0 1终点 T N
那么知道 当 i=T,J=N时,说明已经在这个站了,那么等待时间为0,而i=T j等于其他的时候为无穷大(等待时间)
那么现在逆推
AC代码如下:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF=301;
const int stationnumber=101;
bool isok[INF][stationnumber][2] ; //用来判断该时刻是不是有车
int d1[55],d2[55];
int dp[INF][stationnumber];
int main()
{
int N;
int kase=1;
while( cin>>N && N ){
memset(isok,0,sizeof(isok));
int T;
cin>>T;
int t[25];
for(int i=1;i<N;i++)
cin>>t[i];
// t[1]= 1-2 time t[2]=2-3 time
int M1,M2;
cin>>M1;
for(int i=1;i<=M1;i++){
cin>>d1[i];
isok[d1[i]][1][0]=1; //第一个站,这个时间,有车
int totaltime=d1[i];
for(int j=1;j<N;j++){
totaltime+=t[j];
isok[totaltime][j+1][0]=1; // 第j+1个站,这个时间,有车
}
}
cin>>M2;
for(int i=1;i<=M2;i++){
cin>>d2[i];
isok[d2[i]][N][1]=1; //从第N站开过来的车,这个时间,有车
int totaltime=d2[i];
for(int j=N;j>1;j--){ //从 N-N-1的时间是 t[N-1] 依次类推
totaltime+=t[j-1];
isok[totaltime][j-1][1]=1;
}
}
dp[T][N]=0; //当i=T,j=N时,已经在这个站了,等待时间为0
for(int i=1;i<N;i++)
dp[T][i]=INF;// INF 代表无穷大,可以用来作为一个标志,说明这个时候不可能到站,很明显是这样的。
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 && isok[i][j][0] && i+t[j]<=T) //这个决策是坐左边的车,如果j<N(因为在N的时候没有坐车的意义,并且i+t[j]<=T.
dp[i][j]=min(dp[i][j],dp[i+t[j]][j+1]);
//逆推!这个状态肯定是从坐车后那个时间点在那个车站的状态加上坐车的时间来的。
if(j>1 && isok[i][j][1] && i+t[j-1]<=T) //这个决策是坐右边来的车。
//同理,也是逆推!
dp[i][j]=min(dp[i][j],dp[i+t[j-1]][j-1]);
}
}
cout<<"Case Number "<<kase++<<": ";
if(dp[0][1]>=INF)
cout<<"impossible"<<endl;
else cout<<dp[0][1]<<endl;
}
return 0;
}
2019.3.21补充 状态 d[i][j]表示 剩余i秒,在j站
#include <iostream>
#include <cstring>
using namespace std;
const int MAX =55;
int t[MAX];
bool isok[205][MAX][2]; //某时刻,某个站,哪个方向
int dp[205][MAX];
const int INF = 1e8;
int main()
{
int N;
int kase =1;
while(cin>>N && N){
int T;
cin>>T;
memset(dp,0,sizeof(dp));
memset(isok,0,sizeof(isok));
for(int i=1;i<N;i++){
cin>>t[i];
// t[i]代表 t[i]->t[i+1] 或者说 t[i+1]->t[i];
}
int M1,M2;
cin>>M1;
int x;
for(int i=1;i<=M1;i++){
cin>>x;
int sum=x;
isok[T-x][1][0] = 1;
for(int j=1;j<N;j++){
sum+=t[j]; //时间
if(T-sum>=0)
isok[T-sum][j+1][0] = 1; //往右开的车
}
}
cin>>M2;
for(int i=1;i<=M2;i++){
cin>>x;
int sum=x;
isok[T-x][N][1] = 1; // 往左开的车
for(int j=N;j>=1;j--){
sum+=t[j-1];
if(T-sum>=0)
isok[T-sum][j-1][1] = 1;
}
}
for(int i=1;i<N;i++) dp[0][i] = INF; //记 dp[i][j]为剩余i时间,在j站
for(int i = 1;i<=T;i++){
for(int j=1;j<=N;j++){
dp[i][j] = dp[i-1][j]+1; //等1s; 是从前一秒的状态过来的
if(j-1>0 && i-t[j-1]>=0 && isok[i][j][1]) //这个点可能是从右边来的车(j-1)站的时候坐过来的
dp[i][j] = min(dp[i][j],dp[i-t[j-1]][j-1]);
if(j+1<=N && i-t[j]>=0 && isok[i][j][0] )
dp[i][j] = min(dp[i][j],dp[i-t[j]][j+1]);
}
}
cout<<"Case Number "<<kase++<<": ";
if(dp[T][1]<INF)
cout<<dp[T][1]<<endl;
else cout<<"impossible"<<endl;
}
return 0;
}