UVA 10671 (dp 时间的转化)

首先,要正向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;
}


你可能感兴趣的:(UVA 10671 (dp 时间的转化))