L3-007 天梯地图(测试点2卡住了可以看下)

题目链接

一道Dijkstra的模板题,关于测试点2通不过的问题是没有考虑题目输出的额外的要求:
如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。
1、如果耗费的时间最短的结果有多个,那么选择路径长度最短的。
2、如果路径最短的结果有多个,那么选择经过节点最少的。

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

输入格式:
输入在第一行给出两个正整数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 => … => 终点

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int MaxSize = 1e5 + 5;;
struct Edge {
	int v, len, tm;
};
vector<Edge> E[505];
vector<int> ans[2];
int Ans[2];
bool vis[505];
int dis[505];
int cnt[505];
int pre[505];
void init() {
	memset(vis, false, sizeof(vis));
	memset(dis, 0x3f, sizeof(dis));
	memset(cnt, 0, sizeof(cnt));
	memset(pre, -1, sizeof(pre));
}
void Dijkstra_len(int v1, int v2) {
	init();
	dis[v1] = 0;
	queue<int> Q;
	int v, u,w;
	Q.push(v1);
	while (!Q.empty()) {
		v = Q.front();	Q.pop();
		if (vis[v])	continue;
		vis[v] = true;
		for (int i = 0; i < E[v].size(); i++) {
			u = E[v][i].v, w = E[v][i].len;
			if (dis[u] > dis[v] + w) {
				Q.push(u);
				dis[u] = dis[v] + w;//dis[x]表示起点到x的路程
				cnt[u] = cnt[v] + 1;//cnt[x]表示起点到x的节点数
				pre[u] = v;
			}
			else if (dis[u] == dis[v] + w && cnt[v] + 1 < cnt[u]) {
				cnt[u] = cnt[v] + 1;
				pre[u] = v;
			}
		}
	}
	int ends = v2;
	while (ends != v1) {
		ans[0].push_back(ends);
		ends = pre[ends];
	}
	ans[0].push_back(ends);
	reverse(ans[0].begin(), ans[0].end());
	Ans[0] = dis[v2];
}
void Dijkstra_time(int v1, int v2) {
	init();
	queue<int> Q;
	Q.push(v1);
	dis[v1] = 0;
	int u, v, w,w1;
	while (!Q.empty()) {
		v = Q.front(); Q.pop();
		if (vis[v])	continue;
		vis[v] = true;
		for (int i = 0; i < E[v].size(); i++) {
			u = E[v][i].v, w = E[v][i].tm, w1 = E[v][i].len;
			if (dis[u] > dis[v] + w) {
				Q.push(u);
				dis[u] = dis[v] + w;//dis[x]表示起点到x的耗时
				cnt[u] = cnt[v] + w1;//cnt[x]表示起点到x的路程
				pre[u] = v;
			}
			else if (dis[u] == dis[v] + w && cnt[v] + w1 < cnt[u]) {
				cnt[u] = cnt[v] + w1;
				pre[u] = v;
			}
		}
	}
	int ends = v2;
	while (ends != v1) {
		ans[1].push_back(ends);
		ends = pre[ends];
	}
	ans[1].push_back(ends);
	reverse(ans[1].begin(), ans[1].end());
	Ans[1] = dis[v2];
}
void output(int v1,int v2) {
	if (ans[0] == ans[1]) {
		printf("Time = %d; Distance = %d: ", Ans[1], Ans[0]);
		for (int i = 0; i < ans[0].size(); i++) {
			cout << ans[0][i];
			if (i != ans[0].size() - 1)	cout << " => ";
		}
	}
	else {
		printf("Time = %d: ", Ans[1]);
		for (int i = 0; i < ans[1].size(); i++) {
			cout << ans[1][i];
			if (i != ans[1].size() - 1)	cout << " => ";
		}
		cout << endl;
		printf("Distance = %d: ", Ans[0]);
		for (int i = 0; i < ans[0].size(); i++) {
			cout << ans[0][i];
			if (i != ans[0].size() - 1)	cout << " => ";
		}
	}
}
int main() {
	int N, M,v1,v2,one,len,tm;
	cin >> N >> M;
	while (M--) {
		cin >> v1 >> v2 >> one >> len >> tm;
		E[v1].push_back({ v2,len,tm });
		if (!one)	E[v2].push_back({ v1, len, tm });
	}
	cin >> v1 >> v2;
	Dijkstra_len(v1, v2);
	Dijkstra_time(v1, v2);
	output(v1, v2);
	return 0;
}

总结:对于这种模板题需要熟练掌握模板,这样才能在做题的时候灵活变化。下面给出基本模板:

使用邻接矩阵存储权值

void Dijkstra_(int bg) {
    memset(vis, false, sizeof(vis));
    memset(dis, 0x3f, sizeof(dis));
    for (int i = 0; i < N; i++) {
        if (A[bg][i] < 0x3f3f3f3f) dis[i] = A[bg][i];
    }
    int t, minn;
    vis[bg] = true;
    for (int i = 0; i < N; i++) {
        minn = 0x3f3f3f3f;
        for (int j = 0; j < N; j++) {
            if (!vis[j] && minn > dis[j]) {
                minn = dis[j];
                t = j;
            }
        }
        vis[t] = true;
        for (int j = 0; j < N; j++) {
            if (!vis[j] && dis[j] > dis[t] + A[t][j]) {
                dis[j] = dis[t] + A[t][j];
            }
        }
    }
}

使用邻接表存储权值

void Dijkstra(int bg) {
    memset(vis, false, sizeof(vis));
    memset(dis, 0x3f, sizeof(dis));
    memset(pre, -1, sizeof(pre));
    dis[bg]=0;
    queue<int> Q;
    Q.push(bg);
    int w, u, v;
    while (!Q.empty()) {
        u = Q.front(); Q.pop();
        if (vis[u])  continue;
        vis[u] = true;
        for (int i = 0; i < A[u].size(); i++) {
            v = A[u][i].v, w = A[u][i].w;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                pre[v] = u;
                Q.push(v);
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值