目錄
- 最短路
- 單源最短路
- 樸素Dijkstra
- 堆優化Dijkstra
- Bellman-Ford
- spfa
- 多源匯最短路
- Floyd
- 最小生成樹
- Prim
- Kruskal
- 二分圖
- 染色法
- 匈牙利演算法
最短路
單源最短路
n 為點數, m為邊數
邊權為正:樸素Dijkstra(n * n), 堆優化Dijstra演算法(mlogn),
邊權為負:Bellman-Ford(n * m),spfa(平均o(m),最壞nm),
樸素Dijkstra
用于稠密圖,m 和 n * n 一個級別,
#include<bits/stdc++.h>
/* ----------------------------------------
存盤方式:鄰接矩陣(二維陣列)
s 已經確認最短路的點,
① dist[1] = 0, dist[i] = inf;
② for i : 0 ~ n
t <- 不在s 中的距離最近的點,
s <- t 用t 更新其他所有點的距離,
*///----------------------------------------
using namespace std;
const int N = 510;
int n , m;
int g[N][N];
int dist[N];
bool st[N];
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for(int i = 0;i < n;i ++)
{
int t = -1;
for(int j = 1;j <= n;j ++)
if(!st[j] &&(t == -1 || dist[t] > dist[j]))
t = j;
st[t] = true;
for(int j = 1;j <= n;j ++)
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
if(dist[n] == 0x3f3f3f3f)return -1;
return dist[n];
}
int main()
{
scanf("%d%d", &n, &m);
memset(g, 0x3f ,sizeof g);
while(m --)
{
int a, b , c;
scanf("%d%d%d",&a, &b, &c);
g[a][b] = min(g[a][b], c);
}
int t = dijkstra();
printf("%d\n", t);
return 0;
}
堆優化Dijkstra
用于稀疏圖,m 和 n 一個級別,
#include<bits/stdc++.h>
/* ----------------------------------------
堆優化
存盤方式:鄰接表
s 已經確認最短路的點,
① dist[1] = 0, dist[i] = inf;
② for i : 0 ~ n
t <- 不在s 中的距離最近的點,
s <- t 用t 更新其他所有點的距離,
*///----------------------------------------
using namespace std;
typedef pair<int , int> PII;
const int N = 1000010;
int n , m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c , ne[idx] = h[a] , h[a] = idx ++;
}
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 ,distance = t.first;
if(st[ver]) continue;
else st[ver] = true;
for(int i = h[ver]; i != -1;i = ne[i])
{
int j = e[i];
if(dist[j] > distance + w[i])
{
dist[j] = distance + w[i];
heap.push({dist[j], j});
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while(m --)
{
int a, b , c;
scanf("%d%d%d",&a, &b, &c);
add(a, b ,c);
}
int t = dijkstra();
printf("%d\n", t);
return 0;
}
Bellman-Ford
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 510, M = 10010;
int n , m , k;
int dist[N], backup[N];
struct Edge{
int a , b , w;
}edges[M];
int Bellman_Ford()
{
memset(dist, 0x3f , sizeof dist);
dist[1] = 0;
for(int i = 0;i < k;i ++)
{
memcpy(backup, dist, sizeof dist);
for(int j = 0;j < m;j ++)
{
int a = edges[j].a, b = edges[j].b, w = edges[j].w;
dist[b] = min(dist[b], backup[a] + w);
}
}
if(dist[n] >= 0x3f3f3f3f / 2) return -1;
return dist[n];
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i = 0;i < m;i ++)
{
int a, b ,w;
scanf("%d%d%d", &a,&b,&w);
edges[i] = {a, b, w};
}
int t = Bellman_Ford();
if(t == -1)puts("impossible");
else printf("%d\n", t);
return 0;
}
spfa
#include<bits/stdc++.h>
/* ----------------------------------------
spfa
*///----------------------------------------
using namespace std;
typedef pair<int , int> PII;
const int N = 1000010;
int n , m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
queue<int> q;
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c , ne[idx] = h[a] , h[a] = idx ++;
}
int spfa()
{
memset(dist , 0x3f, sizeof dist);
dist[1] = 0;
q.push(1);
st[1] = true;
while(q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t]; i != -1;i = ne[i])
{
int j = e[i];
if(dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if(!st[j])
{
q.push(j);
st[j] = true;
}
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while(m --)
{
int a, b , c;
scanf("%d%d%d",&a, &b, &c);
add(a, b ,c);
}
int t = spfa();
if(t == -1)puts("impossible");
else printf("%d\n", t);
return 0;
}
多源匯最短路
Floyd
Floyd(n * n * n)演算法
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 210, INF = 1e9;
int n , m , Q;
int d[N][N];
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()
{
scanf("%d%d%d", &n, &m, &Q);
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;
while(m --)
{
int a , b, w;
scanf("%d%d%d", &a , &b ,&w);
d[a][b] = min(d[a][b], w);
}
floyd();
while(Q --)
{
int l , r;
scanf("%d%d", &l, &r);
if(d[l][r] >= INF / 2)puts("impossible");
else printf("%d\n", d[l][r]);
}
return 0;
}
最小生成樹
樸素版本Prim(n ^ n),堆優化(mlogn)
Kruskal(mlogm)
Prim
Kruskal
二分圖
染色法(n + m), 匈牙利演算法(nm, 實際運行時間遠小于nm)
染色法
匈牙利演算法
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/261085.html
標籤:其他
下一篇:第一個JAVA實戰專案!
