题目大意:懒汉需要从A城市开车到B城市去见一个朋友,他的汽车的邮箱的容积L升,车每行驶1公里就要消耗1升油。途中只有在到达一个城市之后才可以找的到加油站并加油,而且懒汉的车很特殊,每次加油只能加满整个邮箱。
懒汉希望途中加油的次数越少越好,当加油的次数相同时,他希望加油所花的钱数越少越好。现在懒汉把地图告诉了你,你能帮帮他吗?可以认为懒汉出发的时候油箱是满的,如果到达 B城市时油箱不是满的,也无需再加油。
假定各地加油站的汽油价格均为Y元/升,如果懒汉想从x城市沿长为z公里的路开车到达y城市,那么离开x城市时汽车至少应还有z升汽油。
Input
输入包含若干组数据,每组数据的第一行有四个正整数N(1<=N<=100),M(1<=M<=1000),L(1<=L<=100),Y(1<=Y<=100),其中N表示地图上一共有N个城市,标号分别为1,2,…,N,M表示N个城市间一共有M条路,L和Y的含义同上。
接下来一行有两个正整数S(1<=S<=N),T(1<=T<=N),分别表示A城市和B城市的标号。
接下来一共有M行,每行有三个正整数x(1<=x<=N),y(1<=y<=N),z(1<=z<=100),表示标号为x的城市和标号为y的城市之间有一条长为z公里的双向道路。
数据组数不超过100组,读入以EOF结束。
Output
对于每组数据,用一行输出一个整数,表示在加油次数最少的前提下,加油所花的最少的钱数。
如果懒汉不能开车到达B城市,输出-1即可。
Sample Input
4 4 6 1
1 4
1 2 3
2 4 4
1 3 2
3 4 6
Sample Output
2
思路:很明显要用到优先队列+bfs。(1)加油次数小的放在前面。(2)总花费少的放在前面。(3)剩余油量多的放在前面。关键是这题对于一个非终结状态的最优判定是模糊的,比如说在同一个点
i
i
i,现在有三个状态:(1)加油次数
2
2
2,花费
120
120
120,剩余油量
0
0
0;(2)加油次数
3
3
3,花费
160
160
160;剩余油量
50
50
50;(3)加油次数
3
3
3,花费
200
200
200,剩余油量
100
100
100。设点
i
i
i距离终点的距离为
100
100
100公里,油价为
1
1
1元每公里,那么最优解其实是(3),次优解是(2),最差的解是(3)。是不是和自己预想的有些出入?因此这题对状态的筛选要宽松一点,只要加油次数、总花费、油量任意一个属性可更新,就应该把该状态放进队列中。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
struct Edge
{
int to,nxt,dis;
}edge[2005];
int n,m,s,t,l,y,tot;
int head[105];
struct node
{
int id,step,v,rest;
node(){}
node(int ii,int ss,int vv,int ll=l)
{
id=ii,step=ss,v=vv,rest=ll;
}
bool operator <(const node &a)const
{
if(step!=a.step)
return step>a.step;
if(v!=a.v)
return v>a.v;
if(rest!=a.rest)
return rest<a.rest;
}
}vis[105];
void addedge(int u,int v,int dis)
{
edge[++tot].to=v,edge[tot].dis=dis,edge[tot].nxt=head[u],head[u]=tot;
}
void bfs()
{
priority_queue<node> q;
q.push(node(s,0,0));
while(!q.empty())
{
node t1=q.top();
q.pop();
bool tag=0;
if(t1.step<vis[t1.id].step)
tag=1,vis[t1.id]=t1;
else if(t1.v<vis[t1.id].v)
tag=1,vis[t1.id]=t1;
else if(t1.rest>vis[t1.id].rest)
tag=1,vis[t1.id]=t1;
if(!tag)
continue;
if(t1.id==t)
{
printf("%d\n",t1.v);
return ;
}
for(int i=head[t1.id];i;i=edge[i].nxt)
{
if(edge[i].dis<=t1.rest)//不用加油
q.push(node(edge[i].to,t1.step,t1.v,t1.rest-edge[i].dis));
q.push(node(edge[i].to,t1.step+1,t1.v+(l-t1.rest)*y,l-edge[i].dis));
}
}
printf("-1\n");
}
int main()
{
while(~scanf("%d%d%d%d",&n,&m,&l,&y))
{
scanf("%d%d",&s,&t);
int u,v,dis;
tot=0;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++)
vis[i]=node(i,INF,INF,0);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&dis);
if(dis>l)
continue;
addedge(u,v,dis),addedge(v,u,dis);
}
bfs();
}
return 0;
}