一个人有一辆车,车有一个油箱,油箱有油量上限,走每条边需要消耗油,每个点可以加油,价格不等。问0到1的最小代价。
以前做这种题是定义d[i][j]当前在第i个点,有j升油,所需的最小代价。现在学了一个新招。
我们知道,在第i个点,到第j个点,有两种加油策略,第一种是加一定的油,使得到j时油为0。第二种是加满油,因为i点的油比较便宜。定义d[i][j]为当前在d第i个点,上一次是第j的点,且在第j的点把油加满,此时的最小代价。在加一个特殊状态d[i][#]表示当前在第i个点,且油为0的最小代价。这样我们拿到一个状态就能算出现在还有多少油。先预处理出两两点对间的最短路就可以从(0,#)到(1,#)求最小代价了。状态n^2,用Dijkstra复杂度n^3logn。本题n小油箱大,适合用这种方法。
#include <bits/stdc++.h>
#define maxn 109
using namespace std;
const int INF=1e9;
const long long inf=1e18;
int n,d[maxn][maxn],mx;
bool inq[maxn],done[maxn][maxn];
long long dis[maxn][maxn],wi[maxn];
char S[100009];
struct node
{
int now,pre;
long long d;
bool operator<(const node &rhs)const
{
return d>rhs.d;
}
node(int now,int pre,long long d)
{
this->now=now;
this->pre=pre;
this->d=d;
}
};
priority_queue<node>Q;
long long Dijkstra()
{
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) dis[i][j]=inf;
memset(done,0,sizeof(done));
while(!Q.empty())Q.pop();
dis[0][n]=0;
Q.push(node(0,n,0));
while(!Q.empty())
{
int now=Q.top().now,pre=Q.top().pre;
Q.pop();
int fuel;
if(pre!=n)
fuel=mx-d[pre][now];
else
fuel=0;
//printf(">>%d %d %lld %d\n",now,pre,dis[now][pre],fuel);
if(done[now][pre])
continue;
done[now][pre]=1;
if(now==1)
return dis[now][pre];
for(int next=0;next<n;next++)
{
if(d[now][next]>mx)
continue;
if(dis[next][now]>dis[now][pre]+(mx-fuel)*wi[now])
{
dis[next][now]=dis[now][pre]+(mx-fuel)*wi[now];
Q.push(node(next,now,dis[next][now]));
}
if(fuel<d[now][next])
{
if(dis[next][n]>dis[now][pre]+(d[now][next]-fuel)*wi[now])
{
dis[next][n]=dis[now][pre]+(d[now][next]-fuel)*wi[now];
Q.push(node(next,n,dis[next][n]));
}
}
}
}
return -1;
}
class LongJourney
{
public: long long minimumCost(vector <int> fuelPrices, int fuelTank, vector <string> roads)
{
n=fuelPrices.size();
mx=fuelTank;
int len=0;
for(int i=0;i<(int)roads.size();i++)
{
for(int j=0;j<(int)roads[i].length();j++)
{
S[len++]=roads[i][j];
}
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i==j)
d[i][j]=0;
else
d[i][j]=INF;
char *p=strtok(S," ");
while(p)
{
int cur=0,last=0,u,v,w;
for(;p[cur]!=',';cur++);
p[cur]=0; u=atoi(p+last);p[cur]=',';last=cur+1;cur++;
for(;p[cur]!=',';cur++);
p[cur]=0;v=atoi(p+last);p[cur]=',';last=cur+1;
w=atoi(p+last);
d[u][v]=min(d[u][v],w);
d[v][u]=min(d[v][u],w);
p=strtok(NULL," ");
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
for(int i=0;i<n;i++)wi[i]=fuelPrices[i];
return Dijkstra();
}
};