这个题目虽然描述的比较麻烦,但是还是不难的,因为t是递增的,所以有拓扑序,那么就可以用dp解了。
dp[i][j][p][q] 表示在i点,j宇宙,p时间,q包盐的最优解。
但是这个题目最大的问题是让人容易用spfa来解,因为复杂度看起来还是可以的。。。。可是tle到死。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=1e2+9,mod=1111111; int dp[maxn][10][222][10]; int dist[maxn]; int pri[10][222]; int n,r; int head[maxn],lon; struct { int to,next,w,p; }e[11111]; int spfa(int m,int limit,int tlimit) { memset(dp,-1,sizeof(dp)); dp[1][1][0][0]=r; for(int t=0,tmp;t<=tlimit;t++) for(int i=1;i<n;i++) for(int j=1;j<=m;j++) { if(i==1&&j!=1) continue; int to=(j+1)%m; if(to==0) to=m; for(int b=0;b<=limit;b++) { tmp=dp[i][j][t][b]; if(tmp<0) continue; // cout<<t<<endl; //cout<<tmp<<endl; dp[i][to][t+1][b]=max(dp[i][to][t+1][b],tmp); if(b>0&&i!=1) dp[i][to][t+1][b-1]=max(dp[i][to][t+1][b-1],tmp+pri[j][i]); if(b<limit&&pri[j][i]<=tmp&&i!=1) dp[i][to][t+1][b+1]=max(dp[i][to][t+1][b+1],tmp-pri[j][i]); for(int k=head[i];k!=-1;k=e[k].next) { int u=e[k].to; if(e[k].w+t>tlimit) continue; if(e[k].p<=tmp) dp[u][j][e[k].w+t][b]=max(dp[u][j][e[k].w+t][b],tmp-e[k].p); if(b>0&&tmp-e[k].p+pri[j][i]>=0&&i!=1) dp[u][j][e[k].w+t][b-1]=max(dp[u][j][e[k].w+t][b-1],tmp-e[k].p+pri[j][i]); if(b<limit&&tmp-e[k].p-pri[j][i]>=0&&i!=1) dp[u][j][e[k].w+t][b+1]=max(dp[u][j][e[k].w+t][b+1],tmp-e[k].p-pri[j][i]); } } } int ans=-1; for(int i=0;i<=tlimit;i++) ans=max(ans,dp[n][1][i][0]); return ans; } void edgeini() { memset(head,-1,sizeof(head)); lon=-1; } void edgemake(int from,int to,int w,int p) { e[++lon].to=to; e[lon].w=w; e[lon].p=p; e[lon].next=head[from]; head[from]=lon; } int main() { // freopen("in.txt","r",stdin); int T,tt=0; scanf("%d",&T); while(T--) { edgeini(); int m,b,k,t; scanf("%d%d",&n,&m); scanf("%d%d",&b,&k); scanf("%d%d",&r,&t); for(int i=1;i<=k;i++) for(int j=1;j<=n;j++) scanf("%d",&pri[i][j]); for(int i=1,from,to,w,p;i<=m;i++) { scanf("%d%d%d%d",&from,&to,&w,&p); edgemake(from,to,w,p); } int ans=spfa(k,b,t); printf("Case #%d: ",++tt); if(ans>=0) cout<<ans<<endl; else printf("Forever Alone\n"); } return 0; }