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≤N≤500), 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 N−1) 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

题意很清楚,给定一张地图,起点和终点,找到起点到终点的两种最短路径
第一是距离最短,如果距离相同,时间最短的优先
第二时间最短,如果时间相同,交叉点(边的条数)少的优先
最后输出的两种最短距离和各自的路径,如果路径相同,只输出一次(特别注意输出格式,有冒号跟分号的细微区别)

这道题需要运行两次dijkstra,如果你把两个函数都写出来的话会发现,整体上代码非常相似,都是两个权重,第一个权重相等时才考虑第二个权重,所以可以对代码进行优化
我一开始写的两个函数的核心代码是这样的
最短距离的代码

if (dist[v] + it[1] < dist[it[0]])
{
    dist[it[0]] = dist[v] + it[1];
    time[it[0]] = time[v] + it[2];
    path[it[0]] = v;
}
else if (dist[v] + it[1] == dist[it[0]] && time[it[0]] > time[v] + it[2])
{
    time[it[0]] = time[v] + it[2];
    path[it[0]] = v;
}

最短时间

if (time[v] + it[2] < time[it[0]])
{
    time[it[0]] = time[v] + it[2];
    num[it[0]] = num[v] + 1;
    path[it[0]] = v;
}
else if (time[v] + it[2] == time[it[0]] && num[it[0]] > num[v] + 1)
{
    num[it[0]] = num[v] + 1;
    path[it[0]] = v;
}

代码重合度非常高,所以同样都是两个权重,代码逻辑都相同,就没有必要写两次同样的函数了,在建图的时候,对每个点建立邻接表,储存它能到达的点的索引,距离,时间,和1,这里的1表示两点之间存在一条边,或者是会形成一个交叉点,符合实际的同时又能和最短距离的代码做相应的替换。
如此建立好图之后,一个点所连出去的边就是一个数组[1,2,3,1],那么在传参数的时候只是两个权重不一样,第一次dijkstra用的权重是距离和时间index=1 、2,第二次用的是时间和交叉点2、 3,所以只需要传递1和2就行了,具体看代码分析。

#include<bits/stdc++.h>
using namespace std;
vector<int> dijkstra(int s, int e, vector<vector<vector<int>>>& graph, int ope, int& ans) {
	vector<int>visited(graph.size()), path(graph.size(), -1), w1(graph.size(), INT_MAX), w2(graph.size(), INT_MAX);
	w1[s] = 0, w2[s] = 0;//第一次w1表示距离,w2表示时间 第二次w1表示时间,w2表示交叉点
	while (!visited[e]) {
		int v = -1, min = INT_MAX;
		for (int i = 0; i < visited.size(); i++)//找到到当前距离(时间)最短的点
			if (!visited[i] && w1[i] < min) {
				min = w1[i];
				v = i;
			}
		if (v == -1) break;
		visited[v] = true;
		for (auto& it : graph[v]) {
			int n = it[0];//表示下一个即将访问的点
			if (visited[n]) continue;//跳过访问过的点
			if (w1[v] + it[ope] < w1[n])//如果起点到v的距离+v到n的距离(时间) 小于起点到v的距离(时间)
			{
				w1[n] = w1[v] + it[ope];//更新距离(时间)
				w2[n] = w2[v] + it[ope + 1];//更新时间(交叉点)
				path[n] = v;//更新路径
			}
			else if (w1[v] + it[ope] == w1[n] && w2[n] > w2[v] + it[ope + 1])//如果起点到v的距离+v到n的距离(时间)
			{//等于起点到v的距离(时间)并且 起点到v的时间(交叉点的)+v到n的时间(交叉点)小于起点到v的时间(交叉点)
				w2[n] = w2[v] + it[ope];//更新时间(交叉点)
				path[n] = v;//更新路径
			}
		}
	}
	vector<int>ret;
	int i;
	for (i = e; path[i] != -1; i = path[i])
		ret.push_back(i);
	ret.push_back(i);
	ans = w1[e];
	return ret;
}
int main()
{
	int n, m, s, e, o, l, t;//点的个数,边的条数,起点,终点,单向,距离,时间
	cin >> n >> m;
	vector<vector<vector<int>>>edge(n);
	for (int i = 0; i < m; i++) {
		cin >> s >> e >> o >> l >> t;
		edge[s].push_back({ e,l,t,1 });
		if (!o)
			edge[e].push_back({ s,l,t,1 });
	}
	cin >> s >> e;
	int dist = 0, time = 0;
	vector<int>ret1 = dijkstra(s, e, edge, 1, dist), ret2 = dijkstra(s, e, edge, 2, time);
	cout << "Distance = " << dist;
	if (ret1 != ret2) {
		cout << ": ";
		for (int i = ret1.size() - 1; i >= 0; i--)
			cout << (i == ret1.size() - 1 ? "" : " -> ") << ret1[i];
		cout << endl;
	}
	else
		cout << "; ";
	cout << "Time = " << time << ": ";
	for (int i = ret2.size() - 1; i >= 0; i--)
		cout << (i == ret2.size() - 1 ? "" : " -> ") << ret2[i];
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值