题目背景
7-28 天梯地图
作者 陈越
单位 浙江大学
本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。
输入格式:
输入在第一行给出两个正整数N
(2 ≤ N
≤ 500)和M
,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M
行,每行按如下格式给出一条道路的信息:
V1 V2 one-way length time
其中V1
和V2
是道路的两个端点的编号(从0到N
-1);如果该道路是从V1
到V2
的单行线,则one-way
为1,否则为0;length
是道路的长度;time
是通过该路所需要的时间。最后给出一对起点和终点的编号。
输出格式:
首先按下列格式输出最快到达的时间T
和用节点编号表示的路线:
Time = T: 起点 => 节点1 => ... => 终点
然后在下一行按下列格式输出最短距离D
和用节点编号表示的路线:
Distance = D: 起点 => 节点1 => ... => 终点
如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。
如果这两条路线是完全一样的,则按下列格式输出:
Time = T; Distance = D: 起点 => 节点1 => ... => 终点
输入样例1:
10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
5 4 0 2 3
5 9 1 1 4
0 6 0 1 1
7 3 1 1 2
8 3 1 1 2
2 5 0 2 2
2 1 1 1 1
1 5 0 1 3
1 4 0 1 1
9 7 1 1 3
3 1 0 2 5
6 3 1 2 1
5 3
输出样例1:
Time = 6: 5 => 4 => 8 => 3
Distance = 3: 5 => 1 => 3
输入样例2:
7 9
0 4 1 1 1
1 6 1 3 1
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 3 1
3 2 1 2 1
4 5 0 2 2
6 5 1 2 1
3 5
输出样例2:
Time = 3; Distance = 4: 3 => 2 => 5
代码长度限制
16 KB
时间限制
300 ms
内存限制
64 MB
栈限制
8192 KB
思路
又是一道dijkstra算法求最小生成树,用优先级队列管理搜索节点,其他方面与广度优先算法一致。。
本题在时间和距离上分别使用dijkstra算法求最小生成树即可。
最大的问题是在时间相同,或者距离相同如何取舍。。
题目的意思是:
- 如果时间相同,则取距离最短的
- 如果距离相同,则取经过点最少的
这两个并不一样,距离最短显然要比经过点最少困难。。。
然后还要记录路径。
综上,需要使用额外的数组。
dijkstra算法求最小时间时,使用到记录节点距离的辅助数组,记录父亲节点的辅助数组。
dijkstra算法求最小距离时,使用到记录节点经过点数的辅助数组,记录父亲节点的辅助数组。
最后不要忘了两个序列一样时是特殊输出。
dijkstra算法在我以前的文章中有讲到,这里不展开了,一些细节可以在下面文章中查看:
https://blog.youkuaiyun.com/Thirty_Bob/article/details/146184754?spm=1001.2014.3001.5502
燃尽了真的燃尽了。。。蒟蒻只能完成到此处了。。。再难一点dijkstra算法蒸的不会了。。。
完整代码
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <string>
using namespace std;
struct node {
int id;
int zhi;
};
struct pnode {
int id; // 点号
int zhi; // 取值
int fa; // 父节点号
int index; // 父节点中的index
friend bool operator<(const pnode &a, const pnode &b) {
return a.zhi > b.zhi;
}
};
vector<node> length[500]; // 长度邻接链表
vector<node> timeG[500]; // 时间邻接链表
int minlen[500], mintime[500]; // d算法生成的结果
int timelen[500]; // 计算时间时的长度
int timefa[500]; // 时间的父节点
int lendian[500]; // 计算距离时的经过点数
int lenfa[500]; // 时间的父节点
void djtime(int a) {
memset(mintime, -1, sizeof(mintime));
memset(timefa, -1, sizeof(timefa));
memset(timelen, 0, sizeof(timelen));
priority_queue<pnode> q;
q.push({a, 0, -1, 0});
while (!q.empty()) {
int nowid = q.top().id;
int nowzhi = q.top().zhi;
int nowfa = q.top().fa;
int nowindex = q.top().index;
q.pop();
if (mintime[nowid] == -1) { // 未被访问过
mintime[nowid] = nowzhi;
if (nowfa == -1) { // 根节点
timelen[nowid] = 0;
timefa[nowid] = -1;
} else {
timelen[nowid] = timelen[nowfa] + length[nowfa][nowindex].zhi;
timefa[nowid] = nowfa;
}
for (int i = 0; i < timeG[nowid].size(); i++) {
if (mintime[timeG[nowid][i].id] == -1) {
q.push({timeG[nowid][i].id, nowzhi + timeG[nowid][i].zhi, nowid, i});
}
}
} else if (mintime[nowid] == nowzhi) { // 访问过,但是新的时间相同,需要比较并取舍
if (timelen[nowid] > timelen[nowfa] + length[nowfa][nowindex].zhi) {
timelen[nowid] = timelen[nowfa] + length[nowfa][nowindex].zhi;
timefa[nowid] = nowfa;
}
for (int i = 0; i < timeG[nowid].size(); i++) {
if (mintime[timeG[nowid][i].id] == -1) {
q.push({timeG[nowid][i].id, nowzhi + timeG[nowid][i].zhi, nowid, i});
}
}
}
}
}
void djlen(int a) {
memset(minlen, -1, sizeof(minlen));
memset(lenfa, -1, sizeof(lenfa));
memset(lendian, 0, sizeof(lendian));
priority_queue<pnode> q;
q.push({a, 0, -1, 0});
while (!q.empty()) {
int nowid = q.top().id;
int nowzhi = q.top().zhi;
int nowfa = q.top().fa;
int nowindex = q.top().index;
q.pop();
if (minlen[nowid] == -1) { // 未被访问过
minlen[nowid] = nowzhi;
if (nowfa == -1) { // 根节点
lendian[nowid] = 0;
lenfa[nowid] = -1;
} else {
lendian[nowid] = lendian[nowfa] + 1;
lenfa[nowid] = nowfa;
}
for (int i = 0; i < length[nowid].size(); i++) {
if (minlen[length[nowid][i].id] == -1) {
q.push({length[nowid][i].id, nowzhi + length[nowid][i].zhi, nowid, i});
}
}
} else if (minlen[nowid] == nowzhi) { // 访问过,但是新的距离相同,需要比较并取舍
if (lendian[nowid] > lendian[nowfa] + 1) {
lendian[nowid] = lendian[nowfa] + 1;
lenfa[nowid] = nowfa;
}
for (int i = 0; i < length[nowid].size(); i++) {
if (minlen[length[nowid][i].id] == -1) {
q.push({length[nowid][i].id, nowzhi + length[nowid][i].zhi, nowid, i});
}
}
}
}
}
int main() {
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++) {
int a, b, type, len, tim;
cin >> a >> b >> type >> len >> tim;
if (type == 0) {
length[b].push_back({a, len});
timeG[b].push_back({a, tim});
}
length[a].push_back({b, len});
timeG[a].push_back({b, tim});
}
int a, b;
cin >> a >> b;
djtime(a);
int index = b;
vector<int> outtime;
while (timefa[index] != -1) {
outtime.push_back(index);
index = timefa[index];
}
djlen(a);
index = b;
vector<int> outlen;
while (lenfa[index] != -1) {
outlen.push_back(index);
index = lenfa[index];
}
bool same = false;
if (outlen.size() == outtime.size()) {
same = true;
for (int i = 0; i < outlen.size(); i++) {
if (outlen[i] != outtime[i]) {
same = false;
break;
}
}
}
if (same) {
cout << "Time = " << mintime[b] << "; Distance = " << minlen[b] << ": " << a;
for (int i = outtime.size() - 1; i >= 0; i--) {
cout << " => " << outtime[i];
}
} else {
cout << "Time = " << mintime[b] << ": " << a;
for (int i = outtime.size() - 1; i >= 0; i--) {
cout << " => " << outtime[i];
}
cout << endl;
cout << "Distance = " << minlen[b] << ": " << a;
for (int i = outlen.size() - 1; i >= 0; i--) {
cout << " => " << outlen[i];
}
}
}