1. 程式人生 > 其它 >最小生成樹 邊權非負

最小生成樹 邊權非負

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;
}