题目链接:http://pat.zju.edu.cn/contests/pat-a-practise/1018
此题算比较难的,第一求最短路径,最短路径有多条时,要选出送出自行车最少的,当送出自行车最少的不止一个时,要选送回自行车最少的。
我的思想:首先看到题,第一反应就是Dijkstra最短路径求,这么做需要在做Dij的同时,保存每个节点的相关信息,这样一次遍历足以。为了保存相应结点信息,设计了如下的数据结构。 map<int, vector<pair<Node, vector<int>>>> info; 描述如下图:
map键值对key对应节点值,value为vector<pair<Node, vector<int>>>类型,用来存多条最短路径,Node 结点用来存collect和sent,vector<int>用来存取其中一条最短路径走过的所有节点(不包括自身)。
剩下的工作就是在Dij时更新数据,在此说明下,有一点要注意的:若每个站点的perfect station = 5, 有如下最短路径序列, 2 3 6 5 1 8,第一次提交有2个case没过是因为如下思想,首先定义collect=0,走到2时,2-5=-3,代表需要从原点取3辆自行车,collect += -3, 然后, 3-5=-2,collect+=-2,以此类推,最后得collect=-5,表格如下,
2 | 3 | 6 | 5 | 1 | 8 |
-3 | -5 | -4 | -4 | -8 | -5 |
误以为需要从原点取5个自行车就够了,其实是错的。是因为车子是从前往后送的,不能用后面的补前面的!!正确的思路是这样的,2的时候需要3个,3的时候需要5个,以此类推,在1的时候需要8个,这时候需要量达到最大,所以需要从原点取8个自行车,所以用sent值来存储collect变化序列中最小的,当sent的值为负时,就代表需要从原点取自行车。
接下来的问题就是求送回多少量,送回辆数 = -sent-(-collect)=collect-sent=-5-(-8)=3, 送回3辆,其实就是collect代表如果能拿后面的自行车来补前面的还需多少辆,而sent代表从前往后送至少送多少辆就足以。所以两者相减代表送回的车数。还有一种简单的情况如下:
5 | 6 | 5 | 7 | 8 | 9 |
0 | 1 | 0 | 3 | 6 | 11 |
这种情况就是collect不会出现负值,就是代表不需要从原点取车,这种情况比较简单,而送回的车数就等于collect最后的值。
主要思想如上,然后就是当找到一点较短路径时,将节点信息复制(i = kk),并做相应的collect ,sent值更新,以及将前驱结点加入vector<int>中, 若找到相同距离的路径,将此结点信息加入到目标节点中(kk的信息加入到i的信息中),再做类似更新。
最后直接找到S结点的信息,对所有最短路径排序选出最优,输出即可。
1 #include<iostream> 2 #include<map> 3 #include<utility> 4 #include<vector> 5 #include<algorithm> 6 using namespace std; 7 8 #define INF 9999999 9 10 struct Node 11 { 12 int sent; 13 int collect; 14 }; 15 16 /*排序谓词函数,用于选出最优路径,即是送出自行车最少,送回自行车最少*/ 17 bool comp(pair<Node, vector<int>> p1, pair<Node, vector<int>> p2) 18 { 19 if(p1.first.sent > p2.first.sent) 20 return true; 21 else if(p1.first.sent == p2.first.sent && p1.first.collect < p2.first.collect) 22 return true; 23 else 24 return false; 25 } 26 27 void Dijkstra_version(vector<vector<int>> &gra, vector<int> &bike, int C, int S) 28 { 29 int start = 0; 30 vector<int> used(gra.size(), 0); 31 map<int, vector<pair<Node, vector<int>>>> info; 32 /*保存每个结点的信息,信息表明到此结点有几条最短路径, 33 分别是什么,以及需要从原点取及其放回多少量自行车*/ 34 vector<int> ri; 35 Node n={INF, 0}; 36 pair<Node, vector<int>> zero(n,ri); 37 info[0].push_back(zero); 38 /*更新原点信息*/ 39 vector<int> dist(gra.size(), INF); 40 dist[0] = 0; 41 42 while(start != S) 43 { 44 int min = INF; int kk = -1; 45 for(int i=0; i<dist.size(); ++i) 46 if(used[i] == 0 && dist[i] < min) 47 { 48 min = dist[i]; 49 kk = i; 50 } 51 used[kk] = 1; 52 for(int i=0; i<dist.size(); ++i) 53 if(used[i] == 0) 54 if(gra[kk][i] + dist[kk] < dist[i]) 55 { 56 dist[i] = gra[kk][i] + dist[kk]; 57 /*当有较短路径出现时,替换原来结点的信息*/ 58 info[i] = info[kk]; 59 for(int j=0; j < info[i].size(); ++j) 60 { 61 /*替换后,对结点的信息更新,collect记录信息,此信息现在虽无具体意义, 62 但是后面要用它计算送回多少量自行车,sent用来记录从原来送出多少自行车*/ 63 info[i][j].first.collect += (bike[i] - C/2); 64 if(info[i][j].first.collect < info[i][j].first.sent) 65 info[i][j].first.sent = info[i][j].first.collect; 66 info[i][j].second.push_back(kk); 67 } 68 } 69 else if(gra[kk][i] + dist[kk] == dist[i] && dist[i] != INF) 70 { 71 /*要把KK结点的信息更新并加入i节点中*/ 72 for(int j=0; j < info[kk].size(); ++j) 73 { 74 info[i].push_back(info[kk][j]); 75 info[i][info[i].size()-1].first.collect += (bike[i] - C/2); 76 if(info[i][info[i].size()-1].first.collect < info[i][info[i].size()-1].first.sent) 77 info[i][info[i].size()-1].first.sent = info[i][info[i].size()-1].first.collect; 78 info[i][info[i].size()-1].second.push_back(kk); 79 } 80 } 81 start = kk; 82 } 83 for(int i=0; i<info[S].size(); ++i) 84 { 85 /*若sent>=0,则代表不需要送出自行车,负数代表要送出自行车*/ 86 if(info[S][i].first.sent >= 0) 87 info[S][i].first.sent = 0; 88 else 89 { 90 /*更新collect,使collect最终表示有多少辆车要送回去*/ 91 info[S][i].first.collect -= info[S][i].first.sent; 92 } 93 } 94 sort(info[S].begin(), info[S].end(), comp); 95 /*排序得最优*/ 96 pair<Node, vector<int>> v=*(info[S].begin()); 97 cout<<0-v.first.sent<<" "; 98 for(int i=0; i<v.second.size(); ++i) 99 cout<<v.second[i]<<"->"; 100 cout<<S<<" "<<v.first.collect<<endl; 101 } 102 103 int main() 104 { 105 int C, N, S, M; 106 while(cin>>C>>N>>S>>M) 107 { 108 vector<int> colum(N+1, INF); 109 vector<vector<int>> gra(N+1, colum); 110 vector<int> bikes(N+1,-1); 111 for(int i=1; i<=N; ++i) 112 cin>>bikes[i]; 113 for(int i=0; i<M; ++i) 114 { 115 int a,b,c; cin>>a>>b>>c; 116 gra[a][b]=gra[b][a]=c; 117 } 118 Dijkstra_version(gra, bikes, C, S); 119 } 120 return 0; 121 }