最小生成树

#include <bits/stdc++.h>
using namespace std;
#define MAX 200
#define INF 0x7fffffff
//无向图,规定两点间只有一条边
//下标从1开始
int graph[MAX+1][MAX+1],points[MAX+1],numbian,numdian,circle[MAX+1];
struct mydata
{
    int from,to,cost;
    mydata(int from,int to,int cost){
        this->from=from;
        this->to=to;
        this->cost=cost;
    }
    mydata(){}
    bool operator<(const mydata &a){
        return this->cost<a.cost;
    }
};

void prim(){
    //加点法
    mydata data[MAX+1];
    int ok[MAX+1];
    memset(ok,0,sizeof(ok));
    for(int i=1;i<=numdian;i++){
        data[i].from=i;
        data[i].to=1;
        data[i].cost=graph[i][1];
    }
    //从点1开始
    ok[1]=1;
    for(int i=0;i<numdian-1;i++){
        int min=-1;
        for(int j=2;j<=numdian;j++){
            //注意这里
            if(!ok[j]&&(min==-1||data[j].cost<data[min].cost)) min=j;
        }
        for(int j=2;j<=numdian;j++){
            //其他所有没加进去的点和这个点的距离
            if(!ok[j]&&graph[min][j]!=-1&&graph[min][j]<data[j].cost){
                data[j].cost=graph[min][j];
                data[j].to=min;
            }
        }
        ok[min]=1;
        cout<<data[min].from<<" -> "<<data[min].to<<endl;
    }
    //结果即在data中,有n-1条边
}

//适合稀疏的图
void kruskal(){
    //加边法
    int circle[MAX+1],k=1;//区分连通分量
    mydata data[MAX+1];
    for(int i=1;i<=numdian;i++) circle[i]=i;
    for(int i=1;i<=numdian;i++){
        for(int j=i;j<=numdian;j++){
            if(graph[i][j]!=INF){
                data[k].cost=graph[i][j];
                data[k].from=i;
                data[k].to=j;
                k++;
            }
        }
    }
    sort(data+1,data+numbian+1);
    //注意左闭右开区间形式
    for(int i=1;i<=numbian;i++){
        if(circle[data[i].from]!=circle[data[i].to]){
            cout<<data[i].from<<" -> "<<data[i].to<<endl;
        //更新circle
        int p=circle[data[i].to];
        for(int j=1;j<=numdian;j++){
            //反例!!,这样写不可以,因为circle[data[i].to]的值动态变化,不能比较
            //目的:把所有是to的分量改为from的,但是to本身也会变呀,导致后续比较都错误
            // if(circle[j]==circle[data[i].to])
            //     circle[j]=circle[data[i].from];
            if(circle[j]==p)
                circle[j]=circle[data[i].from];
        }
        }
    }
}


//kruskal更新一次,查找多次的版本
//并查集
// int func(int x){
//     //这是一个技巧,因为连通分量数组circle初始化为
//     //1 2 ... n,即为每个点的编号,那么对于circle[i]有
//     //(1)circle[i]==i,代表他就没变过,所以连通分量编号就是i
//     //(2)circle[i]!=i,代表被合并了,i合并到了circle[i]里,在返回(1)看看;
//     //返回值是对应的circle[i]==i的点,修改的也是这个点;
//     //并且修改所有的circle[x] != x的点;
//     return circle[x] == x ? x : circle[x] = func(circle[x]);
// }
// //改成循环
// int func1(int x){
//     if(circle[x] == x) return x;
//     int k=x;
//     int *changes=new int[numdian],index=0;
//     while (circle[k] != k)
//     {
//         changes[index++]=k;
//         k=circle[k];
//     }
//     for(int i=0;i<index;i++) circle[changes[i]]=k;
//     delete[] changes;
//     return circle[k];
// }

// bool find(int x,int y){
//     //找是否在同一个连通分量
//     //circle按照点的顺序创建
//     return func(x)==func(y);
// }
// void kruskal(){
//     //加边法
//     int k=1;//区分连通分量
//     mydata data[MAX+1];
//     for(int i=1;i<=numdian;i++) circle[i]=i;
//     for(int i=1;i<=numdian;i++){
//         for(int j=i;j<=numdian;j++){
//             if(graph[i][j]!=INF){
//                 data[k].cost=graph[i][j];
//                 data[k].from=i;
//                 data[k].to=j;
//                 k++;
//             }
//         }
//     }
//     sort(data+1,data+numbian+1);
//     //注意左闭右开区间形式
//     for(int i=1;i<=numbian;i++){
//         if(!find(data[i].from,data[i].to)){
//             cout<<data[i].from<<" -> "<<data[i].to<<endl;
//             circle[data[i].to]=circle[data[i].from]
//         }
//     }
// }

int main(){
    cin>>numdian>>numbian;
    for(int i=1;i<=numdian;i++)
        for(int j=1;j<=numdian;j++)
            graph[i][j]=INF;
    for(int i=1;i<=numdian;i++) points[i]=i;
    for(int i=0;i<numbian;i++){
        int x,y,z;
        cin>>x>>y>>z;
        graph[x][y]=graph[y][x]=z;
    }
    for(int i=1;i<=numdian;i++){
        for(int j=1;j<=numdian;j++)
            cout<<graph[i][j]<<" ";
        cout<<endl;
    }

    // prim();
    kruskal();
    return 0;
}
原文地址:https://www.cnblogs.com/MorrowWind/p/13056634.html