[poj1724]Roads
DarthVictor 人气:0欢迎回来,这里是做图论已经做到疯了的爱上了图论的Darth Victor。没错今天又是图论题,最近一直在刷图论。
题目
Bob and Alice used to live in the city 1. After noticing that Alice was cheating in the card game they liked to play, Bob broke up with her and decided to move away - to the city N. He wants to get there as quickly as possible, but he is short on cash.
We want to help Bob to find the shortest path from the city 1 to the city N that he can afford with the amount of money he has.
Input
The second line contains the integer N, 2 <= N <= 100, the total number of cities.
The third line contains the integer R, 1 <= R <= 10000, the total number of roads.
Each of the following R lines describes one road by specifying integers S, D, L and T separated by single blank characters :
- S is the source city, 1 <= S <= N
- D is the destination city, 1 <= D <= N
- L is the road length, 1 <= L <= 100
- T is the toll (expressed in the number of coins), 0 <= T <=100
Notice that different roads may have the same source and destination cities.
Output
If such path does not exist, only number -1 should be written to the output.
Sample Input
5 6 7 1 2 2 3 2 4 3 3 3 4 2 4 1 3 4 1 4 6 2 1 3 5 2 0 5 4 3 2
Sample Output
11
解说
没错这是一个英文题。现解释一下题意。一个住在1号城市的男的由于某种原因和女朋友吵架决定彻底决裂并远走高飞,走得越远越好。由于只有N座城市他决定跑到N号城市。可惜的是他的经济脉搏都掌握在女朋友手里拿不回来所以他身上只剩几文小钱。但是路是别人的开的你想走得要钱吧,于是给了一张图,每条路有长度,有过路费,问你这位同志凭他身上的钱能不能从1号城市跑到N号城市?如果可以的话最多路程是多少?
输入也大概就这样,第一行是身上的钱,第二行是城市数,第三行是道路数,之后输入每条路的信息。如果他能到N就输出最短路的长度,否则输出-1。
那么可见,这个最短路有两个限制条件,一个是资金,一个是路程,并且资金优先于路程,即在资金满足的情况下再去找最短路。既然多了一个限制,那么应该在跑最短路的时候加一个筛选条件即可。迪杰特斯拉算法是按边依次松弛到每一个点的距离的算法,那么它在这里用起来就十分方便,因为我们在松弛和入队时加上限制条件即可。但是难点就在于,这个限制条件应该怎么加?最开始我想的是在新长度小于原长度的更新条件下再加一条:在新长度小于原长度且走到现在用的资金小于原来走到这里的资金两者都满足时,才能更新,并且一旦累计资金超额也直接continue掉,这样跑一遍完整的迪杰特斯拉时就能找到答案。
但是不对。
仔细想想,这不符合之前提到的资金优先于路程,而是把两个条件当成了同等级的。在假如有两条路可以到达一个点,一个资金少路程长,另一个花钱多路程短,但两个资金都足以到达终点,那么我的算法会选择路程长的路,不符合要求,这显然不可以。
再想一想别的办法。记得怎么优化迪杰特斯拉吗?对,用优先队列,这保证了每次我们取出来的边都是目前最短的。那既然这样我们应该就可以把路程限制去掉,一旦搜到终点就直接return,这样的话因为我们每次取出来的边都是最小的,就能保证我们第一次搜到终点时的路程是最小的。当然,在搜的时候也是要加限制的,即一旦累计资金超出限额就不能松弛,这样的话我们就能保证到达时资金在限额内且路程最短。
代码
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<iostream> 6 #include<queue> 7 #include<stack> 8 using namespace std; 9 const int maxn=100+5; 10 int head[maxn],tot,v,n,m; 11 struct edge{ 12 int len,to,next,money; 13 }e[10000+5]; 14 void Add(int from,int to,int len,int money){ 15 e[tot].money=money; 16 e[tot].len=len; 17 e[tot].next=head[from]; 18 e[tot].to=to; 19 head[from]=tot; 20 tot++; 21 } 22 struct node{ 23 int num,dis,time; 24 node(int x,int y,int z){ 25 num=x; 26 dis=y; 27 time=z; 28 } 29 bool operator<(const node &a) const{ 30 return dis>a.dis; 31 } 32 }; 33 int Dijs(){ 34 priority_queue<node> q; 35 q.push(node(1,0,0)); 36 while(!q.empty()){ 37 node p=q.top();q.pop(); 38 int k=p.num; 39 if(k==n){ 40 return p.dis; 41 } 42 for(int i=head[k];i;i=e[i].next){ 43 int to,len,u; 44 to=e[i].to; 45 len=p.dis+e[i].len; 46 u=p.time+e[i].money; 47 if(u<=v){ 48 q.push(node(to,len,u)); 49 continue; 50 } 51 } 52 } 53 return 0x3f3f3f3f; 54 } 55 int main(){ 56 tot=1; 57 scanf("%d%d%d",&v,&n,&m); 58 for(int i=1;i<=m;i++){ 59 int from,to,len,money; 60 scanf("%d%d%d%d",&from,&to,&len,&money); 61 Add(from,to,len,money); 62 } 63 int ans=Dijs(); 64 if(ans==0x3f3f3f3f) printf("-1"); 65 else printf("%d",ans); 66 }
幸甚至哉,歌以咏志。
加载全部内容