文章目录
小标题的超链接为原题链接,点击跳转
8. 图论
最短路问题(shortest-path problem)是图论中的经典问题之一,可用来解决管路铺设、线路安装、厂区布局和设备更新等实际问题。
基本内容是:假设网络中的每条边都有一个 权重(常用长度、成本、时间等表示),最短路问题的目标是找出 给定两点(通常是源节点和汇节点)之间总权重之和最小的路径。
8.1 遍历
题目
代码
// 树的重心
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1E5+10, M = N*2;
int h[N], e[M], ne[M], idx;
bool st[N];
int n;
int ans = N;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
return;
}
int dfs(int u)
{
st[u] = true;
int sum = 1, res = 0; // 以u为根节点,sum保留所有子树+根节点的重量和,res保留u作为重心时的最大点数和
for(int i=h[u]; i!=-1; i=ne[i])
{
int j = e[i];
if(!st[j])
{
int s = dfs(j);
sum += s;
res = max(res, s);
}
}
res = max(res, n-sum);
ans = min(ans, res);
return sum;
}
int main()
{
memset(h, -1, sizeof h);
cin >> n;
for(int i=1; i<=n-1; i++)
{
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1);
cout << ans;
}
8.2 dijkstra求最短路
路径
题目
代码
// 路径
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2100;
int g[N][N];
int st[N];
int dist[N];
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for(int i=1; i<=2021; i++)
{
// 找到不在st数组里的最小的点
int res = -1;
for(int j=1; j<=2021; j++)
if(!st[j] && (res==-1 || dist[j] < dist[res])) res = j;
// 标记
st[res] = 1;
// 更新所有点
for(int j=1; j<=2021; j++)
dist[j] = min(dist[j], dist[res] + g[res][j]);
}
if(dist[2021] == 0x3f3f3f3f) return -1;
else return dist[2021];
}
int main()
{
// 请在此输入您的代码
memset(g, 0x3f, sizeof g);
for(int i=1; i<=2021; i++)
for(int j=1; j<=2021; j++) if(i != j)
{
int a = i, b = j;
if(abs(a-b) <= 21) g[a][b] = a*b/__gcd(a, b);
}
int t = dijkstra();
cout << t;
return 0;
}
出差
题目
代码
// 出差
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1010;
int g[N][N];
int dist[N];
bool st[N];
int wait[N];
int n, m;
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for(int i=1; i<=n; i++)
{
int res = -1;
for(int j=1; j<=n; j++)
if(!st[j] && (res==-1 || dist[j] < dist[res]))
res = j;
st[res] = 1;
for(int j=1; j<=n; j++)
dist[j] = min(dist[j], dist[res] + g[res][j]);
}
if(dist[n] == 0x3f3f3f3f) return -1;
else return dist[n];
}
int main()
{
cin >> n >> m;
memset(g, 0x3f, sizeof g);
for(int i=1; i<=n; i++) cin >> wait[i];
wait[n] = 0;
for(int i=1; i<=m; i++)
{
int u, v, c;
cin >> u >> v >> c;
if(u == v)
{
g[u][v] = g[v][u] = 0;
continue;
}
g[u][v] = min(g[u][v], c + wait[v]);
g[v][u] = min(g[v][u], c + wait[u]);
}
cout << dijkstra() ;
}
acwing849Dijkstra求最短路Ⅰ
题目
代码
// acwing849Dijkstra求最短路Ⅰ
#include<iostream>
#include<cstring>
using namespace std;
const int N = 5e2+10;
const int M = 1e5+10;
int g[N][N];
int dist[N];
bool st[N];
int n, m;
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for(int i=1; i<=n; i++)
{
int res = -1;
for(int j=1; j<=n; j++)
if(!st[j] && (res==-1 || dist[j] < dist[res]))
res = j;
st[res] = 1;
for(int j=1; j<=n; j++)
dist[j] = min(dist[j], dist[res] + g[res][j]);
}
if(dist[n] == 0x3f3f3f3f) return -1;
else dist[n];
}
int main()
{
memset(g, 0x3f, sizeof g);
cin >> n >> m;
for(int i=1; i<=m; i++)
{
int a, b, c;
cin >> a >> b >> c;
if(a!=b) g[a][b] = min(g[a][b], c);
}
int t = dijkstra();
cout << t;
}
acwing850dijkstra求最短路Ⅱ
题目
代码
// acwing850Dijkstra求最短路Ⅱ
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 200010;
int h[N], e[N], ne[N], w[N], idx;
int dist[N];
bool st[N];
int n, m;
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
while(heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second, dis = t.first;
if(st[ver]) continue;
st[ver] = 1;
for(int i=h[ver]; i!=-1; i=ne[i])
{
int j = e[i];
if(dist[j] > dis + w[i])
{
dist[j] = dis + w[i];
heap.push({dist[j], j});
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
else return dist[n];
}
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m;
for(int i=1; i<=m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
int t = dijkstra();
cout << t;
}
8.4 Floyd求最短路
acwing854Floyd求最短路
题目
代码
// acwing854Floyd求最短路
#include<iostream>
#include<cstring>
using namespace std;
const int N = 210, INF = 1e9;
int d[N][N];
int n, m, k;
void init()
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
if(i == j) d[i][j] = 0;
else d[i][j] = INF;
}
}
void floyd()
{
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
int main()
{
cin >> n >> m >> k;
init();
while(m--)
{
int x, y, z;
cin >> x >> y >> z;
d[x][y] = min(d[x][y], z);
}
floyd();
while(k--)
{
int x, y;
cin >> x >> y;
if(d[x][y] > INF/2) cout << "impossible" << endl;
else cout << d[x][y] << endl;
}
}