7-28 天梯地图 [dijkstra算法 | 天梯赛L3]

题目背景

7-28 天梯地图

作者 陈越

单位 浙江大学

本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。

输入格式:

输入在第一行给出两个正整数N(2 ≤ N ≤ 500)和M,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M行,每行按如下格式给出一条道路的信息:

V1 V2 one-way length time

其中V1V2是道路的两个端点的编号(从0到N-1);如果该道路是从V1V2的单行线,则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];
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值