首先,要正向dp以d(i,j) 代表从i,j到终点的最少耗时,是不可行的,因为这样并不知道最终到达终点的耗时,是否在规定时间内。那么自然想到加上一维表示已经耗时多少。
但这里时间并不一定是整数,需要放大,注意到每次的时间为 L*60/V; v又是5的倍数,所以 只需对分子分母同放大 2520。那么第三维上限为 2520*20;这样变可行。
还有看别人代码,用60先与v进行约分,发现分母剩下 2,3,5,7;所以分子分母放大210倍,只考虑时间上限为1000,所以第三位保险点的话开到210000;但实际运行不会用到这么大。在dp 的时候也对限制时间进行同比放大。这样可以用刷表法,刷出所有可以到达的状态,并维护最优耗油量,时间不需要维护,因为第三维就是时间。
最后只需要在规定时间里扫一遍就可以知道,两个最优方案的解了。
#include <cmath> #include <map> #include <deque> #include <vector> #include <cctype> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,n) for(int (i)=0;(i)<(n);(i)++) #define rep1(i,n) for(int (i)=1;(i)<=(n);(i)++) const int maxn = 11; int n,x,r[maxn],c[maxn],sx,sy,ex,ey,t1,t2; const double eps = 1e-9; const int mod = 2520; const int maxt = 2520*21; double d[maxn][maxn][maxt],cost[maxn][maxn][maxt]; bool vis[maxn][maxn][maxt]; double fee(int i){return x*1.0/(80-0.03*(i*5)*(i*5));} struct node{ int x,y,z; node(int x=0,int y=0,int z=0): x(x),y(y),z(z){} }pa[maxn][maxn][maxt]; double dp2(int i,int j,int k){ if(vis[i][j][k]) return d[i][j][k]; vis[i][j][k] = 1; double& ans =d[i][j][k]; if(i==ex&&j==ey){ double tem = 12.0*x*k/mod; cost[i][j][k] = 0; if(tem>=t1&&tem<=t2) ans = tem; else ans = 1e6; return ans; } ans = 1e6; if(i!=ex){ int ad = (ex > i ? 1:-1); for(int v=1;v<=r[j];v++){ double tem = dp2(i+ad,j,mod/v+k); if(tem < ans){ ans = tem; cost[i][j][k] = cost[i+ad][j][mod/v+k]+fee(v); } else if(tem == ans){ cost[i][j][k] = min(cost[i][j][k],cost[i+ad][j][mod/v+k]+fee(v)); } } } if(j!=ey){ int ad = (ey > j ? 1:-1); for(int v=1;v<=c[i];v++){ double tem = dp2(i,j+ad,mod/v+k); if(tem < ans){ ans = tem; cost[i][j][k] = cost[i][j+ad][mod/v+k]+fee(v); } else if(tem == ans){ cost[i][j][k] = min(cost[i][j][k],cost[i][j+ad][mod/v+k]+fee(v)); } } } return ans; } double dp(int i,int j,int k){ if(vis[i][j][k]) return d[i][j][k]; vis[i][j][k] = 1; double& ans =d[i][j][k]; if(i==ex&&j==ey){ double tem = 12.0*x*k/mod; if(tem>=t1&&tem<=t2){ cost[i][j][k] = tem; d[i][j][k] = 0; } else ans = 1e6; return ans; } ans = 1e6; if(i!=ex){ int ad = (ex > i ? 1:-1); for(int v=1;v<=r[j];v++){ double tem = dp(i+ad,j,mod/v+k)+fee(v); if(tem < ans){ ans = tem; cost[i][j][k] = cost[i+ad][j][mod/v+k]; } else if(tem == ans){ cost[i][j][k] = min(cost[i][j][k],cost[i+ad][j][mod/v+k]); } } } if(j!=ey){ int ad = (ey > j ? 1:-1); for(int v=1;v<=c[i];v++){ double tem = dp(i,j+ad,mod/v+k)+fee(v); if(tem < ans){ ans = tem; cost[i][j][k] = cost[i][j+ad][mod/v+k]; } else if(tem == ans){ cost[i][j][k] = min(cost[i][j][k],cost[i][j+ad][mod/v+k]); } } } return ans; } void init(){ int x1 = min(sx,ex),x2 = max(sx,ex); int y1 = min(sy,ey),y2 = max(sy,ey); for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) for(int k=0;k<maxt;k++) vis[i][j][k] = false; } int main() { int T; scanf("%d",&T); for(int kase=1;kase<=T;kase++){ scanf("%d %d",&n,&x); rep1(i,n) {scanf("%d",&r[i]); r[i]/=5;} rep1(i,n) {scanf("%d",&c[i]); c[i]/=5;} scanf("%d %d %d %d %d %d",&sx,&sy,&ex,&ey,&t1,&t2); printf("Scenario %d:\n",kase); int flag = 1; init(); dp2(sx,sy,0); if(d[sx][sy][0]==1e6){ printf("IMPOSSIBLE\n"); continue; } printf("The earliest arrival: %.0lf minutes, fuel %.2lf gallons\n",ceil(d[sx][sy][0]),cost[sx][sy][0]); init(); dp(sx,sy,0); printf("The economical travel: %.0lf minutes, fuel %.2lf gallons\n",ceil(cost[sx][sy][0]),d[sx][sy][0]); } return 0; }