天梯赛 L2城市间紧急救援L3天梯地图L3直捣黄龙L3地铁一日游保姆级注释题解

Posted 灀龗䯦縷

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了天梯赛 L2城市间紧急救援L3天梯地图L3直捣黄龙L3地铁一日游保姆级注释题解相关的知识,希望对你有一定的参考价值。

L2-001 城市间紧急救援

题干:

​ 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数NMSD,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从SD的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:

2 60
0 1 3

题意:

给定无向图,每个点有权值,求

  1. S点到D点的最短路的数量
  2. 最短路中最大权值并输出该条最短路的路径
思路:

(1)dijkstra求最短路+数组存储路径

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1010;
const int inf = 0x3f3f3f3f;
typedef pair<int, int>PII;
typedef long long ll;

int n, m, s, e;
int w[N][N];//邻接矩阵记录两点直接连线距离
bool st[N];
int d[N];//起始城市到该城市的最短长度
int jy[N];//该城市救援队人数
int rs[N];//这条路线上到此城市的救援队最多人数
int p[N];//记录这条线路上这座城市的前一个城市
int lx[N];//到达此城市的路线数量

void dijkstra() {
	for (int i = 1; i <= n; i++) {
		int t = -1;
		for (int j = 1; j <= n; j++)
			if (!st[j] && (t == -1 || d[t] > d[j]))
				t = j;

		st[t] = true;

		for (int j = 1; j <= n; j++) {
			if (d[j] > d[t] + w[t][j]) {//更新最短路
				d[j] = d[t] + w[t][j];
				lx[j] = lx[t];
				p[j] = t;//记录到达j点的前一个点为t
				rs[j] = rs[t] + jy[j];//到j点的救援队人数为到t点的救援队人数+j点原有人数
			} else if (d[j] == d[t] + w[t][j]) {//最短路相同时
				lx[j] += lx[t];//路线数量叠加
				if (rs[j] < rs[t] + jy[j]) {//若该线路救援队数量更多
					p[j] = t;
					rs[j] = rs[t] + jy[j];
				}

			}
		}
	}
}

int main() {
	cin >> n >> m >> s >> e;
	s++, e++;//习惯把编号从1开始计数
	memset(d, 0x3f, sizeof d);
	d[s] = 0;
	lx[s] = 1;
	memset(w, 0x3f, sizeof w);

	for (int i = 1; i <= n; i++) {
		cin >> jy[i];
		rs[i] = jy[i];
		p[i] = i;//类似并查集的初始化
	}

	while (m--) {
		int a, b, c;
		cin >> a >> b >> c;
		a++, b++;
		w[a][b] = w[b][a] = min(w[a][b], c);
	}
	/*****求最快到达的路线*****/
	dijkstra();

	cout << lx[e] << ' ' << rs[e] << endl;

	/*****存储最快到达的路径*****/
	vector<int>ve;//vector存储路径
	int now = e;//从结束城市向前寻找路径至起始城市
	while (1) {
		ve.push_back(now);
		if (p[now] == now)
			break;

		now = p[now];
	}
	reverse(ve.begin(), ve.end());//翻转
	
	/*****输出*****/
	int f = 0;
	for (auto t : ve) {//输出
		if (f)
			cout << ' ';
		f = 1;
		cout << t - 1 ;
	}
}

(2)floyd求最短路+dfs存储路径

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1010;
typedef pair<int, int>PII;
typedef long long ll;

int n, m, s, e;
int w[N][N];//记录两点之间最短路
int d[N][N];//记录两点直接连通的路径
int cnt;//记录最短路径条数
int maxn;//最多救援队数量
int jy[N];
vector<int>ve;//当前路径
vector<int>maxv;//最长路径

void floyd() {//弗洛伊德算法求两点之间最短路
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++) {
				w[i][j] = min(w[i][j], w[i][k] + w[k][j]);
			}
}

void dfs(int s, int rs) {//寻找路径,s为当前点,rs为当前人数
	rs += jy[s];
	if (e == s) {//递归退出条件
		if (maxn < rs) {
			maxn = max(maxn, rs);
			maxv = ve;
		}
		cnt++;

		return;
	}

	for (int i = 1; i <= n; i++) {
		if (w[s][i] != 0x3f3f3f3f && w[s][i] != 0
		        && w[s][e] == d[s][i] + w[i][e]) { //不能w[s][e] == w[s][i] + w[i][e],要保证s和i有直接路径相通
			ve.push_back(i);
			dfs(i, rs);
			ve.pop_back();
		}
	}

}

int main() {
	cin >> n >> m >> s >> e;
	s++, e++;
	for (int i = 1; i <= n; i++)//弗洛伊德初始化
		for (int j = 1; j <= n; j++) {
			if (i == j)
				d[i][j] = w[i][j] = 0;
			else
				d[i][j] = w[i][j] = 0x3f3f3f3f;
		}

	for (int i = 1; i <= n; i++)
		cin >> jy[i];
	while (m--) {
		int a, b, c;
		cin >> a >> b >> c;
		a++, b++;
		w[a][b] = w[b][a] = min(w[a][b], c);
		d[a][b] = d[b][a] = min(d[a][b], c);
	}
	floyd();
	ve.push_back(s);
	dfs(s, 0);
	cout << cnt << ' ' << maxn << endl;
	int f = 0;
	for (auto t : maxv) {
		if (f)
			cout << ' ';
		cout << t - 1;
		f = 1;
	}


}

L3-007 天梯地图

题干:

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

输入格式:

输入在第一行给出两个正整数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

题意:

给定图,图中有有向边和无向边,每个点有权值,求

  1. 起点到终点的最短路及其路径
  2. 起点到终点最少耗时路及其路径
思路:

dijkstra跑两次分别求最短路和最少耗时路+数组存储路径+vector存储最终路径并判断两条线路是否相同

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1010;
const int inf = 0x3f3f3f3f;
typedef pair<int, int>PII;
typedef long long ll;

int n, m, s, e;
int w[N][N];//邻接矩阵记录两点直接连线距离
int co[N][N];//邻接矩阵记录两点直接连线时间
bool st[N];//记录该点是否被松弛过
int d[N];//记录最短路程
int si[N];//记录该线路到达该点时经过的节点数
int ti[N];//记录最短时间
int p[N];//记录这条线路上这座城市的前一个城市

void dijkstra1() {//求时间最短
	memset(st, 0, sizeof st);
	for (int i = 1; i <= n; i++) {
		int t = -1;
		for (int j = 1; j <= n; j++) {
			if (!st[j] && (t == -1 || ti[t] > ti[j]))
				t = j;
		}
		st[t] = true;

		for (int j = 1; j <= n; j++) {
			if (ti[j] > ti[t] + co[t][j]) {//更新最短时间路
				ti[j] = ti[t] + co[t][j];
				p[j] = t;
				d[j] = d[t] + w[t][j];
			} else if (ti[j] == ti[t] + co[t][j]) {//最短时间路相同时求最短距离路
				if (d[j] > d[t] + w[t][j]) {
					p[j] = t;
					d[j] = d[t] + w[t][j];
				}

			}
		}
	}
}


void dijkstra2() {//求路程最短
	memset(st, 0, sizeof st);
	memset(d, 0x3f, sizeof d);//重置最短路
	d[s] = 0;
	fill(si, si + n + 10, 1);
	for (int i = 1; i <= n; i++) {
		int t = -1;
		for (int j = 1; j <= n; j++) {
			if (!st[j] && (t == -1 || d[t] > d[j]))
				t = j;
		}
		st[t] = true;

		for (int j = 1; j <= n; j++) {
			if (d[j] > d[t] + w[t][j]) {//更新最短距离路
				d[j] = d[t] + w[t][j];
				si[j] = si[t] + 1;
				p[j] = t;
			} else if (d[j] == d[t] + w[t][j]) {//最短距离路相同时求最少节点路
				if (si[j] > si[t] + 1) {
					p[j] = t;
					si[j] = si[t] + 1;
				}

			}
		}
	}
}

int main() {
	cin >> n >> m;

	memset(d, 0x3f, sizeof d);
	memset(ti, 0x3f, sizeof ti);
	memset(w, 0x3f, sizeof w);
	memset(co, 0x3f, sizeof co);

	while (m--) {
		int aa, bb, cc, dd, ee;
		cin >> aa >> bb >> cc >> dd >> ee;
		aa++, bb++;
		if (cc) {
			w[aa][bb] = min(w[aa][bb], dd);
			co[aa]以上是关于天梯赛 L2城市间紧急救援L3天梯地图L3直捣黄龙L3地铁一日游保姆级注释题解的主要内容,如果未能解决你的问题,请参考以下文章

天梯赛 L2城市间紧急救援L3天梯地图L3直捣黄龙L3地铁一日游保姆级注释题解

天梯赛 L2城市间紧急救援L3天梯地图L3直捣黄龙L3地铁一日游保姆级注释题解

天梯赛 L2-001 紧急救援

团体程序设计天梯赛-练习集 L2-001 紧急救援 (25 分)

天梯赛2016-L2

天梯赛题解 L1-049 天梯赛座位分配