关于最短路的学习
最短路题单:
山东理工大学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();
}
}
/*
*/