最短路径题目练习
目录
一、蓝桥公园 1121-floyd算法
题目描述
完整代码 (滚动数组优化后的)
二、蓝桥王国1122-dijkstra算法
题目描述
完整代码
三、最短路问题3828- floyd算法
题目描述
完整代码
四、慈善晚会3035-dijkstra算法
题目描述
完整代码
往期参考文章链接,看这个就好啦:
图论--最短路问题总结-CSDN博客
一、蓝桥公园 1121-floyd算法
题目描述
完整代码 (滚动数组优化后的)
#include<bits/stdc++.h>
using namespace std;
const long long INF = 1e18;
int main() {
int n, m, q;
cin >> n >> m >> q;
vector<vector<long long>> dist(n+1, vector<long long>(n+1, INF));
// 初始化:自己到自己是0
for(int i=1; i<=n; i++) dist[i][i] = 0;
// 处理输入,保留最小边
while(m--) {
int u, v, w;
cin >> u >> v >> w;
if(w < dist[u][v]) { // 处理重边
dist[u][v] = w;
dist[v][u] = w; // 无向图
}
}
// Floyd核心
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
// 处理查询
while(q--) {
int st, ed;
cin >> st >> ed;
if(dist[st][ed] == INF) cout << -1 << endl;
else cout << dist[st][ed] << endl;
}
return 0;
}
二、蓝桥王国1122-dijkstra算法
题目描述
完整代码
//dijkstra
/*
1. 输入处理:读取节点数n和边数m,构建邻接表。
2. 初始化距离数组mindis,起点(节点1)的距离设为0,其他为LLONG_MAX。
3. 使用优先队列(小根堆)来存储当前的最短距离和节点。
4. 进入主循环,每次取出堆顶元素,进行松弛操作。
5. 松弛过程中更新相邻节点的最短距离,并将新的距离压入堆中。
6. 在每次处理完当前节点后,输出所有节点的当前最短距离。
*/
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int n,m;
cin>>n>>m;
//邻接表存储图 u{v,w}
vector<vector<pair<int ,int>>> grid(n+1);
//存储图,m条边
for(int i=0;i<m;i++)
{
int u,v,w;
cin>>u>>v>>w;
grid[u].emplace_back(v,w); //单向边 ,无重边
}
//初始化距离数组
vector<ll> mindis(n+1,LLONG_MAX);
mindis[1]=0;
//小根堆:每次弹出数值最小的
priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<>> pq; //每次弹出当前节点与相邻节点的最短路径
pq.emplace(0,1);//距离,结点
//算法
while(!pq.empty())
{
auto [dis,cur] = pq.top();
pq.pop();
if(mindis[cur]>dis) continue;
//松弛:遍历从cur 出发的所有点
for(auto [v,w] : grid[cur])
{
if(mindis[cur]+w<mindis[v])
{
mindis[v]=mindis[cur]+w;
//将新的最短距离压入队列
pq.emplace(mindis[v],v);
}
}
}
//输出最短路径的距离
for(int i=1;i<=n;i++)
{
if (i > 1) cout << " ";
if(mindis[i]==LLONG_MAX) cout<<"-1";
else cout<<mindis[i];
}
return 0;
}
此题邻接表优化空间【
n=3e5
时,邻接矩阵需要3e5×3e5=9e10
个元素的存储空间,按每个元素8字节(long long
)计算,总内存需求约为720,000 GB,远超任何合理内存限制】大规模稀疏图还要将朴素的O(N²)搜索改为优先队列优化
使用邻接矩阵存储的代码
#include<bits/stdc++.h>
using namespace std;
#define INF INT_MAX
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n, m;
cin >> n >> m;
// 初始化图,默认所有路径为INT_MAX(表示无穷大)
vector<vector<pair<int, int>>> adj(n + 1); // adj[u] 存储 (v, w) 表示从 u 到 v 权重为 w
// 输入图的边
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
adj[u].push_back({v, w});
}
// 初始化最短距离数组
vector<int> mindist(n + 1, INF);
mindist[1] = 0;
// 使用优先队列 (min-heap),存储 {距离, 节点}
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, 1}); // 从节点 1 开始,距离为 0
// Dijkstra 算法
while (!pq.empty()) {
int u = pq.top().second;
int dist_u = pq.top().first;
pq.pop();
// 如果当前节点的最短距离已经被访问过,跳过
if (dist_u > mindist[u]) continue;
// 更新与当前节点相邻的节点的最短距离
for (auto& edge : adj[u]) {
int v = edge.first;
int weight = edge.second;
if (mindist[u] + weight < mindist[v]) {
mindist[v] = mindist[u] + weight;
pq.push({mindist[v], v});
}
}
}
// 输出结果
for (int i = 1; i <= n; i++) {
if (mindist[i] == INF) {
cout << "-1 ";
} else {
cout << mindist[i] << " ";
}
}
return 0;
}
but:..........
三、最短路问题3828- floyd算法
题目描述
完整代码
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
//求最大公因数
int gcd(int a,int b)
{
return (b==0)?a:gcd(b,a%b);
}
//求最小公倍数
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
//质数
bool iszhishu(int x)
{
if(x==1) return false;//1不是质数
if(x==2) return true;//2是唯一的偶质数
if (x % 2 == 0) return false; // 排除其他偶数
for(int i=3;i<=sqrt(x);i+=2) /// 从3开始,每次加2(跳过偶数)
{
if(x%i==0) return false; //发现因数,不是质数
}
return true;// 没有因数
}
int main() {
int n, q;
cin >> n >> q;
// 初始化所有点对的邻接矩阵,权值为INF
vector<vector<int>> dist(n+1, vector<int>(n+1, INF));
// 构建边
for (int i = 1; i <= n; ++i) {
for (int j = i+1; j <= n; ++j) { // 保证i < j,满足第一个条件
bool a = iszhishu(i), b = iszhishu(j);
if ((a && !b) || (!a && b)) { // 恰好一个质数,满足第二个条件
dist[i][j] = lcm(i, j); // 单向边i->j,权值为最小公倍数
}
}
}
// Floyd算法核心
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
}
}
}
// 处理q个查询
while (q--) {
int a, b;
cin >> a >> b;
if (dist[a][b] == INF) cout << -1 << endl;
else cout << dist[a][b] << endl;
}
return 0;
}
结合了一点数学思维。。。 掌握了求最大公因数、最小公倍数、判断质数的数学知识,自己没想到的点是使用Floyd算法一次性计算所有点对之间的最短路径!!(因为所有点都是在n以内的 i<n j<n)最后直接查询即可(还是太年轻啊.......)
四、慈善晚会3035-dijkstra算法
题目描述
完整代码
/*
题目大意:
n个节点,m条边(有重边、单向边),起点为p,不可达至为INF,
输出 该结点-->起始点 + 起始点-->该结点 来回的最大cost 【能去不一定能回.....需要存储正反图】
max( 到达某节点的最短路径 + 从该节点返回 p 的最短路径 )
*/
/*
解题思路:
1. 使用 Dijkstra 算法计算单源最短路径:
- `dis1` 存储从 p 到所有节点的最短路径。
- `dis2` 存储从所有节点返回到 p 的最短路径。
- 因为是单向边所以需要构造**正向图和反向图**。
2. 计算最大往返代价:
- 遍历所有节点,计算 `dis1[i] + dis2[i]`,取最大值。
- 若节点不可达,则路径长度视为 INF
*/
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const ll INF = 1061109567;
void Dijkstra(int p, vector<ll>& mindist, vector<vector<pair<int,int>>>& adj) {
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<>> pq;
mindist[p] = 0;
pq.push({0, p}); // 优先队列存储 (距离, 节点)
while (!pq.empty()) {
auto [dist,cur] = pq.top(); pq.pop();
if (dist > mindist[cur]) continue; // 如果当前路径大于已知最短路径,则跳过
for (auto [v,w] : adj[cur]) {
if (mindist[v] > mindist[cur] + w) { // 松弛操作
mindist[v] = mindist[cur] + w;
pq.push({ mindist[v],v});
}
}
}
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);
int n, m, p;
cin >> n >> m >> p;
vector<vector<pair<int,int>>> e1(n+1),e2(n+1); // 存储正向图与反向图
vector<ll> dis1(n + 1, INF), dis2(n + 1, INF);// 初始化最短路径为 INF
while(m--) {
int u, v, w;
cin >> u >> v >> w;
e1[u].push_back({v, w}); // 正向图
e2[v].push_back({u, w}); // 反向图
}
Dijkstra(p, dis1, e1);
Dijkstra(p, dis2, e2);
ll res = 0;
for (int i = 1; i <= n; i++) {
ll to_i = (dis1[i] == INF ? INF : dis1[i]); // p → i
ll from_i = (dis2[i] == INF ? INF : dis2[i]); // i → p
res = max(res, to_i + from_i); // 计算最大往返路径
}
cout << res << endl;
return 0;
}
第一次做到需要用到正反图的........自己真的考虑不到这个点(可能我很chun)