关于最短路的学习

最短路题单:

山东理工大学2024年 全国天梯赛专题强化训练赛1---最短路
题目链接

题目抽象,要素颇多,对于最短路的联系简直是折磨!

一般多是维护的不只是最短路单个状态,可能融合了最短路条数,顶点集合,或者其他的多中变量。

直捣黄龙

首当其冲的是直捣黄龙,需要维护三个状态,世中之世

直捣黄龙

代码利用了较多的stl,方便解题

#include<bits/stdc++.h>
using namespace std;
struct node {
	string v;
	int w;
};
map<string, vector<node>> g;
map<string, int> dis, ren;
map<string, int>cheng, di, ans;
string qi, zh;
map<string, string> pr;
map<string, bool> st;
int n, m;
set<string> se;
void dijkstra() {
	priority_queue<pair<int, string>, vector<pair<int, string>>, greater<pair<int, string>>> q;
	ans[qi] = 1;
	for (auto s : se) {
		dis[s] = 1e9;
	}
	q.push({0, qi});
	dis[qi] = 0;
	while (q.size()) {
		auto u = q.top().second;
		q.pop();
		if (st[u] != 0)
			continue;
		st[u] = 1;
		for (auto e : g[u]) {
			string v = e.v;
			int w = e.w;
			//路径最短
			if (dis[v] > dis[u] + w) {
				//转移
				dis[v] = dis[u] + w;
				cheng[v] = cheng[u] + 1;
				di[v] = di[u] + ren[v];
				ans[v] = ans[u];
				q.push({dis[v], v});
				pr[v] = u;
			} else if (dis[v] == dis[u] + w) {
				//路径相同判断城市
				ans[v] += ans[u];
				//城市尽可能多
				if (cheng[v] < cheng[u] + 1) {
					cheng[v] = cheng[u] + 1;
					di[v] = di[u] + ren[v];
					pr[v] = u;
				} else if (cheng[v] == cheng[u] + 1) {
					//城市相同,杀敌最多
					if (di[v] < di[u] + ren[v]) {
						di[v] = di[u] + ren[v];
						pr[v] = u;
					}
				}
			}
		}
	}
}
int main() {
	cin >> n >> m >> qi >> zh;
	se.insert(qi);
	for (int i = 1; i < n; i++) {
		string s;
		int x;
		cin >> s >> x;
		se.insert(s);
		ren[s] = x;
	}
	pr[qi] = "-1";
	for (int i = 1; i <= m; i++) {
		string u, v;
		int x;
		cin >> u >> v >> x;
		g[u].push_back({v, x});
		g[v].push_back({u, x});

	}
	dijkstra();
	//输出城市名字
	string be = zh;
	vector<string> lu;
	while (be != "-1") {
		lu.push_back(be);
		be = pr[be];
	}
	for (int i = lu.size() - 1; i >= 0; i--) {
		if (i != lu.size() - 1)
			cout << "->";
		cout << lu[i];
	}
	cout << '\n';
	cout << ans[zh] << ' ' << dis[zh] << ' ' << di[zh];
}

城市救援

比较融合的题

城市救援

这个题融合了最短路计数和顶点集合,不仅要统计最短路径的条数,同时要记录经过的顶点,这两部分在洛谷分别是绿和黄,相当有难度,但是在提单中算简单的。

代码直接引用队友YC同学的

#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int N = 1100;
int n, idx, m, cnt, res;
int f[N];
typedef pair<int, int>PII;
int st[N];
int dist[N];
int ans[N];//最短路径条数
int a[N];//输入
int sum[N];//救援队数
int q[N];  //这个点父节点
int c, d;
void print(int x) {
	if (x == c) printf("%d", x);
	else {
		print(q[x]);
		printf(" %d", x);
	}
}
vector<pair<int, int>> g[N];
void solve() {

	cin >> n >> m >> c >> d;
	for (int i = 0; i <= n - 1; i++) {
		cin >> a[i];
	}
	ans[c] = 1;
	sum[c] = a[c];
	q[c] = -1;
	priority_queue<PII, vector<PII>, greater<PII>> que;

	memset(st, 0, sizeof st);
	memset(dist, 0x3f, sizeof dist);
	for (int i = 1; i <= m; i++) {
		int l, r, v;
		cin >> l >> r >> v;
		g[l].push_back({r, v});
		g[r].push_back({l, v});
	}
	dist[c] = 0;
	que.push({0, c});
	while (que.size()) {
		int u = que.top().second;
		que.pop();
		if (st[u])
			continue;
		st[u] = 1;
		for (auto it : g[u]) {
			int l = it.first;
			int r = it.second;
			if (dist[l] > dist[u] + r) {
				ans[l] = ans[u];
				dist[l] = dist[u] + r;
				sum[l] = sum[u] + a[l];
				q[l] = u;
				que.push({dist[l], l});
			} else if (dist[l] == dist[u] + r) {
				ans[l] += ans[u];
				if (sum[l] < sum[u] + a[l]) {
					sum[l] = sum[u] + a[l];
					q[l] = u;
				}
			}
		}
	}
	cout << ans[d] << " " << sum[d] << endl;
	print(d);
}
signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;
	// cin >> t;
	while (t--) {
		solve();
	}
}


自己写的代码,还是自己写的好。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int q[N];
int n, m, be, en;
//最短路条数,节点
int ans[N], pr[N];
//救援队数
int sum[N];
int dis[N];
bool st[N];
vector<pair<int, int>> g[N];
void dijkstra() {
	memset(dis, 0x3f, sizeof dis);
	priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> qu;
	ans[be] = 1;
	sum[be] = q[be];
	dis[be] = 0;
	qu.push({0, be});
	while (qu.size()) {
		auto u = qu.top().second;
		qu.pop();
		if (st[u] == 1)
			continue;
		st[u] = 1;
		for (auto e : g[u]) {
			int v = e.first;
			int w = e.second;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				ans[v] = ans[u];
				pr[v] = u;
				sum[v] = sum[u] + q[v];
				qu.push({dis[v], v});
			} else if (dis[v] == dis[u] + w) {
				ans[v] += ans[u];
				if (sum[v] < sum[u] + q[v]) {
					sum[v] = sum[u] + q[v];
					pr[v] = u;
				}
			}
		}
	}
}
int main() {
	cin >> n >> m >> be >> en;
	for (int i = 0; i < n; i++) {
		cin >> q[i];
	}
	pr[be] = -1;
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		g[u].push_back({v, w});
		g[v].push_back({u, w});
	}
	dijkstra();
	cout << ans[en] << ' ' << sum[en] << '\n';
	int x = en;
	vector<int> puth;
	while (x != -1) {
		puth.push_back(x);
		x = pr[x];
	}
	for (int i = puth.size() - 1; i >= 0; i--) {
		if (i != 0)
			cout << puth[i] << ' ';
		else
			cout << puth[i];
	}
}

旅行规划

数据比较小,可以直接用floyd,这是第一个做出来的题,其实后面的题思路上也基本上大差不差,做的时候一直没处理好sum。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define haha puts("")
#define ye puts("Yes")
#define no puts("No")
const int N = 1e6 + 10;
const int M = 10100;
const int mod = 998244353;
int n, m;
//int a[N];
//int b[N];
int dis[N];
bool st[N];
int cnt = 0;
int sum[500][500];
int g[500][500];

void solve() {
	int n, m, s, d;
	cin >> n >> m >> s >> d;
	memset(g, 0x3f3f3f3f, sizeof(g));
	for (int i = 0; i < n; i++)
		g[i][i] = 0, sum[i][i] = 0;
	for (int i = 1; i <= m; i++) {
		int a, b, c, d;
		cin >> a >> b >> c >> d;
		if (c < g[a][b])
			g[a][b] = g[b][a] = c;
		sum[a][b] = sum[b][a] = d;
	}
	//floyd
	for (int k = 0; k < n; k++)
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++) {
				if (g[i][j] > g[i][k] + g[k][j]) {
					g[i][j] = g[i][k] + g[k][j];
					sum[i][j] = sum[i][k] + sum[k][j];
				} else if (g[i][j] == g[i][k] + g[k][j]) {
					sum[i][j] = min(sum[i][j], sum[i][k] + sum[k][j]);
				}
			}
	cout << g[s][d] << ' ' << sum[s][d] << endl;
}

signed main() {
//	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;
//	cin >> t;
	while (t--) {
		solve();
	}
}
/*
*/

Harry Potter's Exam

看了题解才明白了题意,用\(floyd\)即可

找到所有最短路径后再进行遍历,去找符合题目要求的那个路径。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define haha puts("")
#define ye puts("Yes")
#define no puts("No")
const int N = 1e6 + 10;
const int M = 10100;
const int mod = 998244353;
int n, m;
int q[N];
//int b[N];
int dis[N];
bool st[N];
int cnt = 0;
int g[500][500];

void solve() {
	cin >> n >> m;
	memset(g, 0x3f, sizeof g);
	for (int i = 1; i <= m; i++) {
		int a, b, c;
		cin >> a >> b >> c;
		g[a][b] = g[b][a] = c;
	}
	for (int k = 1; k <= n; k++) {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
			}
		}
	}
	int mi = 1e18, bian = 0;
	for (int i = 1; i <= n; i++) {
		int ma = 0;
		int f = 1;
		for (int j = 1; j <= n; j++) {
			if (j == i) continue;
			if (g[i][j] == 1e18) {
				f = 0;
				break;
			}
			if (g[i][j] > ma) {
				ma = g[i][j];
			}
		}
		if (f != 0) {
			if (ma != 0 && ma < mi) {
				mi = ma;
				bian = i;
			}
		}
	}
	if (mi == 1e18)
		cout << 0 << '\n';
	else
		cout << bian << ' ' << mi << '\n';
}

signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;
//	cin >> t;
	while (t--) {
		solve();
	}
}
/*
*/
posted @ 2024-07-05 17:44  ZhangDT  阅读(25)  评论(0)    收藏  举报