PAT甲级——1111 Online Map (单源最短路经的Dijkstra算法、priority_queue的使用)

 
1111 Online Map (30 分)
 

Input our current position and a destination, an online map can recommend several paths. Now your job is to recommend two paths to your user: one is the shortest, and the other is the fastest. It is guaranteed that a path exists for any request.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers N (2), and M, being the total number of streets intersections on a map, and the number of streets, respectively. Then M lines follow, each describes a street in the format:

V1 V2 one-way length time

where V1 and V2 are the indices (from 0 to N1) of the two ends of the street; one-way is 1 if the street is one-way from V1 to V2, or 0 if not; length is the length of the street; and time is the time taken to pass the street.

Finally a pair of source and destination is given.

Output Specification:

For each case, first print the shortest path from the source to the destination with distance D in the format:

Distance = D: source -> v1 -> ... -> destination

Then in the next line print the fastest path with total time T:

Time = T: source -> w1 -> ... -> destination

In case the shortest path is not unique, output the fastest one among the shortest paths, which is guaranteed to be unique. In case the fastest path is not unique, output the one that passes through the fewest intersections, which is guaranteed to be unique.

In case the shortest and the fastest paths are identical, print them in one line in the format:

Distance = D; Time = T: source -> u1 -> ... -> destination

Sample Input 1:

10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
3 4 0 3 2
3 9 1 4 1
0 6 0 1 1
7 5 1 2 1
8 5 1 2 1
2 3 0 2 2
2 1 1 1 1
1 3 0 3 1
1 4 0 1 1
9 7 1 3 1
5 1 0 5 2
6 5 1 1 2
3 5

Sample Output 1:

Distance = 6: 3 -> 4 -> 8 -> 5
Time = 3: 3 -> 1 -> 5

Sample Input 2:

7 9
0 4 1 1 1
1 6 1 1 3
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 1 3
3 2 1 1 2
4 5 0 2 2
6 5 1 1 2
3 5

Sample Output 2:

Distance = 3; Time = 4: 3 -> 2 -> 5

 题目大意:给定一个有向有权图,求最短路径和最快路径,若两条最短路径相同则输出时间短的那条路径,若两条最快路径相同则输出经过的节点少的那条,若最短路径和最快路径相同,则输出路径长度、时间和路径节点。题目里的one-way指的是当前的两个节点v1、v2是否为单向路径。

思路:两次Dijkstra即可,采用邻接表+堆优化(使用C++的queue容器,priority_queue本质上就是一个堆,不嫌麻烦的也可以手写堆的操作)的Dijkstra算法,题目里面对每条路径都有两个优先级的要求,所以需要在struct里面设置变量的优先级。

核心就是Dijkstra算法,一下子看不懂的话可以将教材上的DIjkstra算法人肉实现几遍然后仔细阅读源码。先学习最原始的使用邻接矩阵的未优化版本,然后改用邻接表并加入堆的优化,这里不得不赞美一下强大的stl,如果没有priority_queue的话还需要手撸一个堆,代码越长越容易出bug,毕竟人类是有极限的啊(我不做人了,JOJO!)。

  1 #include <iostream>
  2 #include <unordered_map>
  3 #include <vector>
  4 #include <queue>
  5 #define INFI 10000
  6 #define MaxVNum 500
  7 using namespace std;
  8 struct ENode {
  9     int length = INFI, time = INFI;
 10 } E[MaxVNum][MaxVNum];//
 11 struct distNode {
 12     int u, dist = INFI, time = INFI;
 13     friend bool operator < (const distNode &a, const distNode &b) {
 14         return a.dist != b.dist ? a.dist > b.dist : a.time > a.time;
 15     }
 16 };
 17 struct timeNode {
 18     int u, time = INFI, num = INFI;
 19     friend bool operator < (const timeNode &a, const timeNode &b) {
 20         return a.time != b.time ? a.time > b.time : a.num > b.num;
 21     }
 22 };
 23 vector <int> V[MaxVNum];//顶点
 24 int sPath[MaxVNum], fPath[MaxVNum];//分别记录最短路径和最快路径
 25 int DijkstraDis(int sour, int des, int N);
 26 int DijkstraTime(int sour, int des, int N);
 27 void printPath(vector <int> &v, int &size);//将逆序路径顺序输出
 28 int main()
 29 {
 30     int N, M, sour, des;
 31     scanf("%d%d", &N, &M);
 32     for (int i = 0; i < M; i++) {
 33         int v1, v2, flag, len, time;
 34         scanf("%d%d%d%d%d", &v1, &v2, &flag, &len, &time);
 35         V[v1].push_back(v2);
 36         E[v1][v2].length = len;
 37         E[v1][v2].time = time;
 38         if (!flag) {
 39             V[v2].push_back(v1);
 40             E[v2][v1].length = len;
 41             E[v2][v1].time = time;
 42         }
 43     }
 44     scanf("%d%d", &sour, &des);
 45     int dis = DijkstraDis(sour, des, N);
 46     int time = DijkstraTime(sour, des, N);
 47     vector <int> ans1, ans2;
 48     for (int x = des; x != -1; x = sPath[x])
 49         ans1.push_back(x);
 50     for (int x = des; x != -1; x = fPath[x])
 51         ans2.push_back(x);
 52     int size1 = ans1.size(), size2 = ans2.size();
 53     bool flag = true;
 54     if (size1 == size2) {
 55         for (int i = 0; i < size1; i++) {
 56             if (ans1[i] != ans2[i]) {
 57                 flag = false;
 58                 break;
 59             }
 60         }
 61     }
 62     if (size1 == size2 && flag) {
 63         printf("Distance = %d; Time = %d:", dis, time);
 64         printPath(ans1, size1);
 65     }
 66     else {
 67         printf("Distance = %d:", dis);
 68         printPath(ans1, size1);
 69         printf("Time = %d:", time);
 70         printPath(ans2, size2);
 71     }
 72     return 0;
 73 }
 74 void printPath(vector <int> &v, int &size) {
 75     for (int i = size - 1; i >= 0; i--) {
 76         printf(" %d", v[i]);
 77         if (i > 0) {
 78             printf(" ->");
 79         }
 80     }
 81     printf("\n");
 82 }
 83 int DijkstraTime(int sour, int des, int N) {
 84     vector <bool> collected(N, false);
 85     vector <int> time(N,INFI), num(N,INFI);
 86     priority_queue <timeNode> Q;
 87     int u, w;
 88     for (u = 0; u < N; u++)
 89         fPath[u] = -1;
 90     timeNode vertex;
 91     vertex.u = sour;
 92     vertex.time = time[sour] = 0;
 93     vertex.num = num[sour] = 0;
 94     Q.push(vertex);
 95     while (!Q.empty()) {
 96         vertex = Q.top();
 97         Q.pop();
 98         u = vertex.u;
 99         collected[u] = true;
100         for (int i = 0; i < V[u].size(); i++) {
101             w = V[u][i];
102             if (!collected[w]) {
103                 if (time[u] + E[u][w].time < time[w] || (time[u] + E[u][w].time == time[w] && num[u] + 1 < num[w])) {
104                     time[w] = time[u] + E[u][w].time;
105                     num[w] = num[u] + 1;
106                     fPath[w] = u;
107                     vertex.u = w;
108                     vertex.time = time[w];
109                     vertex.num = num[w];
110                     Q.push(vertex);
111                 }
112             }
113         }
114     }
115     return time[des];
116 }
117 int DijkstraDis(int sour, int des, int N) {
118     vector <bool> collected(N, false);
119     vector <int> dist(N,INFI), time(N,INFI);
120     priority_queue <distNode> Q;
121     distNode vertex;
122     int u, w;
123     for (w = 0; w < N; w++)
124         sPath[w] = -1;
125     vertex.u = sour;
126     vertex.dist = dist[sour] = 0;
127     vertex.time = time[sour] = 0;
128     Q.push(vertex);
129     while (!Q.empty()) {
130         vertex = Q.top();
131         Q.pop();
132         u = vertex.u;
133         collected[u] = true;
134         for (int i = 0; i < V[u].size(); i++) {
135             w = V[u][i];
136             if (!collected[w]) {
137                 if (dist[u] + E[u][w].length < dist[w] || (dist[u] + E[u][w].length == dist[w] && time[u] + E[u][w].time < time[w])) {
138                     dist[w] = dist[u] + E[u][w].length;
139                     time[w] = dist[u] + E[u][w].time;
140                     sPath[w] = u;
141                     vertex.u = w;
142                     vertex.dist = dist[w];
143                     vertex.time = time[w];
144                     Q.push(vertex);
145                 }
146             }
147         }
148     }
149     return dist[des];
150 }

 


posted @ 2019-05-14 23:20  大众名字重名太多  阅读(159)  评论(0编辑  收藏  举报