PAT甲级 1111 - Online Map(最短路)
PAT甲级1111
题目链接 https://www.patest.cn/contests/pat-a-practise/1111
【题意】
输入当前的位置和目的地,在线地图可以推荐几条路径。现在你的任务是向用户推荐两条路径:一条最短,另一条最快,输入确保有解。
【输入格式】
单组输入,第一行分别给出两个正整数N(2 <= N <= 500)和M,分别是地图上的结点总数和街道的数量。然后按照M行,每一行都按照以下格式描述一条街道:
起点 终点 单程 长度 时间
其中起点和终点是街道两端的结点编号(从0到N-1)如果街道从起点到终点为单向,则单程值为1,否则为0。长度是街道的长度,时间是通过街道所需的时间。
最后给出一对源和目的地。
【输出格式】
首先以最短距离距离D打印从源到目的地的最短路径,格式为:
Distance = D: source -> v1 -> … -> destination
然后在下一行打印总时间为T的最快路径,格式为:
Time = T: source -> w1 -> … -> destination
在最短路径不唯一的情况下,输出最短路径中最快的路径,这是保证唯一的。如果最快的路径不是唯一的,则输出通过最少路口的路段,这也是保证唯一的。
如果最短路径和最快路径相同,则按以下格式将它们打印在一行中,格式为:
Distance = D; Time = T: source -> u1 -> … -> destination
【思路】
图论中的最短路径问题,分别把距离和时间看成图中边的权值,然后用Dijkstra算法求源点到其它各点的最短路径,同时记录每个点的前驱点。因为根据题中的描述,不论是距离最短的最短路径还是时间最短的最短路径,都不一定是唯一的,所以都需要再额外增加一个限制条件。对于距离最短路径来说,用数组d对距离做松弛操作,如果最短路相同,那么再用一个数组t对时间做松弛操作,即在最短路相同的前提下进一步求最短时间。同理,对于时间最短路径来说也是一样,不过这一次是用数组d对时间做松弛操作,用数组t对到达每个结点的最短路所经过结点的个数做松弛操作,即在时间最短的前提下保证经过的结点数最少。
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 550;
struct Edge {
int from, to, dist, other;
Edge(int f, int t, int d, int o) :from(f), to(t), dist(d), other(o) {}
};
struct HeapNode {
int d, u;
HeapNode(int dd, int uu) :d(dd), u(uu) {}
bool operator<(const HeapNode& rhs)const {
return d > rhs.d;
}
};
struct Dijkstra {
int n, m;
vector<Edge> edges;
vector<int> g[maxn];
vector<int> path;
bool done[maxn];
int d[maxn];
int t[maxn];
int p[maxn];
void init(int n) {
path.clear();
this->n = n;
for (int i = 0; i < n; ++i) g[i].clear();
edges.clear();
}
void add(int from, int to, int dist, int other) {
edges.push_back(Edge(from, to, dist, other));
m = edges.size();
g[from].push_back(m - 1);
}
void dijkstra_Distance(int s) {//计算最短距离
priority_queue<HeapNode> que;
for (int i = 0; i < n; ++i) { d[i] = inf; t[i] = inf; }
d[s] = 0;
t[s] = 0;
memset(done, 0, sizeof(done));
que.push(HeapNode(0, s));
while (!que.empty()) {
HeapNode x = que.top();
que.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = 0; i < g[u].size(); ++i) {
Edge& e = edges[g[u][i]];
if (d[e.to] > d[u] + e.dist) {
d[e.to] = d[u] + e.dist;
t[e.to] = t[u] + e.other;
p[e.to] = g[u][i];
que.push(HeapNode(d[e.to], e.to));
}
else if (d[e.to] == d[u] + e.dist && t[e.to] > t[u] + e.other) {
t[e.to] = t[u] + e.other;
p[e.to] = g[u][i];
}
}
}
}
void dijkstra_Time(int s) {//计算最短时间
priority_queue<HeapNode> que;
for (int i = 0; i < n; ++i) { d[i] = inf; t[i] = inf; }
d[s] = 0;
t[s] = 0;
memset(done, 0, sizeof(done));
que.push(HeapNode(0, s));
while (!que.empty()) {
HeapNode x = que.top();
que.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = 0; i < g[u].size(); ++i) {
Edge& e = edges[g[u][i]];
if (d[e.to] > d[u] + e.dist) {
d[e.to] = d[u] + e.dist;
t[e.to] = t[u] + 1;
p[e.to] = g[u][i];
que.push(HeapNode(d[e.to], e.to));
}
else if (d[e.to] == d[u] + e.dist && t[e.to] > t[u] + 1) {
t[e.to] = t[u] + 1;
p[e.to] = g[u][i];
}
}
}
}
void print(int x) {//递归记录以x为终点的最短路径
if (d[x] == 0) {
path.push_back(x);
return;
}
Edge& e = edges[p[x]];
print(e.from);
path.push_back(x);
}
};
int n, m;
Dijkstra Distance, Time;
int main() {
scanf("%d%d", &n, &m);
Distance.init(n);
Time.init(n);
for (int i = 0; i < m; ++i) {
int from, to, oneway, length, time;
scanf("%d%d%d%d%d", &from, &to, &oneway, &length, &time);
if (oneway == 1) {
Distance.add(from, to, length, time);
Time.add(from, to, time, length);
}
else {
Distance.add(from, to, length, time);
Distance.add(to, from, length, time);
Time.add(from, to, time, length);
Time.add(to, from, time, length);
}
}
int s, t;
scanf("%d%d", &s, &t);
Distance.dijkstra_Distance(s);
Time.dijkstra_Time(s);
Distance.print(t);
Time.print(t);
bool same = true;
if (Distance.path.size() != Time.path.size()) same = false;
else {
for (int i = 0; i < Distance.path.size(); ++i) {
if (Distance.path[i] != Time.path[i]) {
same = false;
break;
}
}
}
if (same) {
printf("Distance = %d; Time = %d: ", Distance.d[t], Time.d[t]);
printf("%d", Distance.path[0]);
for (int i = 1; i < Distance.path.size(); ++i) {
printf(" -> %d", Distance.path[i]);
}
}
else {
printf("Distance = %d: ", Distance.d[t]);
printf("%d", Distance.path[0]);
for (int i = 1; i < Distance.path.size(); ++i) {
printf(" -> %d", Distance.path[i]);
}
printf("\nTime = %d: ", Time.d[t]);
printf("%d", Time.path[0]);
for (int i = 1; i < Time.path.size(); ++i) {
printf(" -> %d", Time.path[i]);
}
printf("\n");
}
return 0;
}