最小生成樹 邊權非負
阿新 • • 發佈:2022-05-15
prim 演算法
使用於領接矩陣版本
與dijkstra極其相似 只是更新的矩陣的數量不同
krukal演算法
並查集
從小到大排序
一條邊沒有聯通 就選擇這條邊
否則 如果聯通就不選擇這條邊
求最大的邊權最小
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int n,m; const int N = 16005; struct edge{ int a,b,w; bool operator<(edge &a){ return w<a.w; } }e[N]; int st[N]; int p[N]; int find(int x){ if(x!=p[x]){ p[x]=find(p[x]); } return p[x]; } int main() { cin >> n>>m; for (int i = 1; i <= n; i ++ ) p[i]=i; for (int i = 1; i <= m; i ++ ){ cin >> e[i].a>>e[i].b>>e[i].w; } int res=0; sort(e+1,e+1+m); for (int i = 1; i <= m; i ++ ){ int a=find(e[i].a),b=find(e[i].b); if(a!=b){ p[a]=b; res=e[i].w; } } cout<<n-1<<" " << res; return 0; }
必連邊 縮點
再列舉非必邊 https://www.acwing.com/activity/content/problem/content/1514/
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int n,m; const int N = 10005; int p[N]; struct edge{ int a,b,w; bool operator<(edge &a ){ return w<a.w; } }e[N]; int find(int x){ if(x!=p[x]){ p[x]=find(p[x]); } return p[x]; } int main() { cin >> n>>m; int res=0,k=0; for (int i = 1; i <= n; i ++ ) p[i]=i; for (int i = 1; i <= m; i ++ ){ int t,a,b,c; cin >> t>>a>>b>>c; if(t==1){ p[find(a)]=p[find(b)]; res+=c; } else{ e[k++]={a,b,c}; } } sort(e,e+k); for (int i = 0; i < k; i ++ ){ int a=find(e[i].a),b=find(e[i].b); if(a!=b){ p[a]=b; res+=e[i].w; } } cout << res; return 0; }
橫豎的連線價值不一樣 優先連線價值小的
https://www.acwing.com/problem/content/1146/
#include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 1010, M = N * N, K = 2 * N * N; int n, m, k; int ids[N][N]; struct Edge { int a, b, w; }e[K]; int p[M]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } void get_edges() { int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}, dw[4] = {1, 2, 1, 2}; for (int z = 0; z < 2; z ++ )//這個是方向 先豎再橫 for (int i = 1; i <= n; i ++ )//這個是座標 for (int j = 1; j <= m; j ++ ) for (int u = 0; u < 4; u ++ )//列舉四個方向 if (u % 2 == z)//對2取模後剛好相等的就是對應的方向上的 { int x = i + dx[u], y = j + dy[u], w = dw[u]; if (x && x <= n && y && y <= m) { int a = ids[i][j], b = ids[x][y]; if (a < b) e[k ++ ] = {a, b, w};//加一次就可以了 可以省點空間 但不加也可以啦 } } } int main() { cin >> n >> m; for (int i = 1, t = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++, t ++ ) ids[i][j] = t; for (int i = 1; i <= n * m; i ++ ) p[i] = i; int x1, y1, x2, y2; while (cin >> x1 >> y1 >> x2 >> y2) { int a = ids[x1][y1], b = ids[x2][y2]; p[find(a)] = find(b); } get_edges(); int res = 0; for (int i = 0; i < k; i ++ ) { int a = find(e[i].a), b = find(e[i].b), w = e[i].w; if (a != b) { p[a] = b; res += w; } } cout << res << endl; return 0; }