最小生成树学习笔记

什么是最小生成树

一个图中可能存在多条相连的边,我们从一个图中挑出一些边生成一棵树(树就是指一个无向连通图不包含回路(连通图中不存在环))。

这仅仅是生成一棵树,还未满足最小,当图中每条边都存在权重时,这时候我们从图中生成一棵树(n - 1 条边)时,生成这棵树的总代价就是每条边的权重相加之和。

Kruskal

首先我们先将这几个点每个独自成为一个集合,将一些连接这些集合的边,按照权值从小到大排序,每次加入最小的边,将边两端的集合合并成一个集合,但要保证这两个点不在同一个集合,而怎么判断他们有没有联通呢,这时,我们就可以用到并查集了。

并查集

详见博客(暂无

然后如果他们在同一个集合就换下一条边。题目详见(P3366

code

#include<bits/stdc++.h>
#define maxn 1000005
using namespace std;
inline int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
int cnt,sum,f[maxn],n,m;
struct rode{
    int x,y,z;
}a[maxn];
int find(int k){
    if(f[k]==k) return k;
    return f[k]=find(f[k]);
}
bool cmp(rode a,rode b){
    return a.z<b.z;
}
int main () {
    cin>>n>>m;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++)
        cin>>a[i].x>>a[i].y>>a[i].z;
    sort(a+1,a+1+m,cmp);
    for(int i=1;i<=m;i++){
        int fx=find(a[i].x),fy=find(a[i].y);
        if(fx==fy) continue;
        f[fy]=fx;
        sum+=a[i].z;
		cnt++;
		if(cnt==n-1) break;
    }
    if(cnt!=n-1) cout<<"orz";
    else cout<<sum;
    return 0;
}

Prim

Prim的主要思路如下:

1.首先从任意一个顶点开始构造最小生成树,并标记那些点已经加入了最小生成树。

2.用dis(假设是dis)存储每个点离生成树的距离。

3.选出离生成树最近的定点加入到生成树中。

一直循环,直到生成树有n个顶点。

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,min,t1,t2,t3;
int e[10005][10005],book[1000005]={0},dis[1000005];
int inf=INT_MAX;
int cnt=0,sum=0;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i==j) e[i][j]=0;
            else e[i][j]=inf;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&t1,&t2,&t3);
        e[t1][t2]=t3;
        e[t2][t1]=t3;
    }
    for(int i=1;i<=n;i++)
        dis[i]=e[1][i];
    int i,j,k;
    book[1]=1;
    cnt++;
    while(cnt<n){
        min=inf;
        for(i=1;i<=n;i++)
            if(book[i]==0&&dis[i]<min){
                min=dis[i];
                j=i;
            }
        book[j]=1;
        sum+=dis[j];
        cnt++;
        for(k=1;k<=n;k++)
            if(book[k]==0&&dis[k]>e[j][k])
                dis[k]=e[j][k];
    }
    printf("%d\n",sum);
    return 0;
 }

posted @ 2023-05-27 16:17  bhbjzyh  阅读(30)  评论(0编辑  收藏  举报