PAT 甲级 1111Online Map

题意:给定一个有向图,第一求最短的路径,如果最短路径不唯一,要求时间最短;第二求时间最短的路径,如果不唯一,要求经过顶点最少的的路径

思路:使用两次dijkstar算法分别计算最短的路径和最短的用时,当使用dijkstar的时候就直接可以计算出到终点的前驱数组,当需要遍历的时候直接遍历前驱数组直接就可以找到起点了;

代码:

#include<iostream>
#include<algorithm>
#include<vector>
const int INF = 99999999;
#define nodes 510
using namespace std;
int n = 0, m = 0, g[nodes][nodes], t[nodes][nodes], dis[nodes], Time[nodes], dispre[nodes], timepre[nodes], weight[nodes], Nodes[nodes], v, u;
vector<int> dispath, timepath;
int start, des;
bool vis[nodes];
void dfsdispath(int v) {//计算总的路径
	dispath.push_back(v);
	if (v == start)return;
	dfsdispath(dispre[v]);
}
void dfstimepath(int v) {//计算总的时间最短的路径
	timepath.push_back(v);
	if (v == start)return;
	dfstimepath(timepre[v]);
}
int main() {
	fill(dis, dis + nodes, INF);
	fill(Time, Time + nodes, INF);
//	fill(weight, weight + nodes, INF);weight也可以不用初始化最大的,因为它只是用于当最短路径相等的时候比较时间的时候用的
	fill(g[0], g[0] + nodes * nodes, INF);
	fill(t[0], t[0] + nodes * nodes, INF);
	cin >> n >> m;
	int x, y, one, len, time;
	for (int i = 0; i < m; i++) {
		scanf("%d%d%d%d%d", &x, &y, &one, &len, &time);
		g[x][y] = len;
		t[x][y] = time;
		if (one == 0) {
			g[y][x] = len;
			t[y][x] = time;
		}
	}
	cin >> start >> des;
	dis[start] = 0;//第一次dijstart算法,计算最短路径
//	for (int i = 0; i < n; i++) {//其实不管3有没有前驱,当访问到3的时候加入了之后,直接返回了,没有影响
//		dispre[i] = i;
//	}
	for (int i = 0; i < n; i++) {//第一次计算最段的路径
		v = INF, u = -1;
		for (int j = 0; j < n; j++) {
			if (dis[j] < v && !vis[j]) {
				v = dis[j], u = j;
			}
		}
		if (u == -1)break;
		vis[u] = true;
		for (int j = 0; j < n; j++) {
			if (!vis[j] && g[u][j] != INF) {
				if (dis[u] + g[u][j] < dis[j]) {
					dis[j] = dis[u] + g[u][j];//dis保存的是到每个顶点的最短距离
					dispre[j] = u;//直接用dispre保存前驱
					weight[j] = weight[u] + t[u][j];//保存weight(最短时间)只是用于比较,本质大小无所谓
				}
				else if (dis[u] + g[u][j] == dis[j] && weight[j] > weight[u] + t[u][j]) {
					dispre[j] = u;
					weight[j] = weight[u] + t[u][j];
				}
			}
		}
	}
	dfsdispath(des);
	fill(vis, vis + nodes, false);//第二次dijkstar算法,计算最短时间
	Time[start] = 0;
	for (int i = 0; i < n; i++) {
		v = INF, u = -1;
		for (int j = 0; j < n; j++) {
			if (Time[j] < v && !vis[j]) {
				v = Time[j], u = j;
			}
		}
		if (u == -1)break;
		vis[u] = true;
		for (int j = 0; j < n; j++) {
			if (!vis[j] && t[u][j] != INF) {
				if (Time[u] + t[u][j] < Time[j]) {
					Time[j] = Time[u] + t[u][j];
					timepre[j] = (u);//保存时间最短的直接前驱
					Nodes[j] = Nodes[u] + 1;//表示通过u到j更短,故更新到j的节点的个数
				}
				else if (Time[u] + t[u][j] == Time[j] && Nodes[j] > Nodes[u] + 1) {
					timepre[j] = (u);
					Nodes[j] = Nodes[u] + 1;
				}
			}
		}
	}
	dfstimepath(des);
	printf("Distance = %d", dis[des]);
	if (dispath == timepath) {
		printf("; Time = %d: ", Time[des]);
	}
	else {
		printf(": ");
		for (int i = dispath.size() - 1; i >= 0; i--) {
			printf("%d", dispath[i]);
			if (i != 0)printf(" -> ");
		}
		printf("\nTime = %d: ", Time[des]);
	}
	for (int i = timepath.size() - 1; i >= 0; i--) {
		printf("%d", timepath[i]);
		if (i != 0)printf(" -> ");
	}
	system("pause");
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值