最小生成树

做题时发现自己只会打(Kruskal) kk/,所以来补课来了

概念

(v) 个点的无向图中,取 (|v| - 1)条边,组成的权值最小的树

prim

mind:

将顶点分为两类,一类是在查找的过程中已经包含在树中的(假设为 A 类),剩下的是另一类(假设为 B 类),起始状态全部顶点都归为 B 类。在找最小生成树时,选定任意一个顶点作为起始点,并将之从 B 类移至 A 类;然后找出 B 类中到 A 类中的顶点之间权值最小的顶点,将之从 B 类移至 A 类,如此重复,直到 B 类中没有顶点为止。所走过的顶点和边就是该连通图的最小生成树

#include<bits/stdc++.h>
using namespace std;
#define re register
#define il inline
il int read()
{
    re 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;
}
#define inf 123456789
#define A 5005
#define B 200005
struct edge{
   int v,w,next;
}e[B<<1];
int head[A],dis[A],cnt,n,m,tot,now=1,ans;
bool vis[B];
il void add(int u,int v,int w)
{
   e[++cnt].v = v;e[cnt].w = w;e[cnt].next = head[u];head[u] = cnt;
}
il void init()
{
    n = read(),m = read();
    for(re int i = 1,u,v,w;i <= m;++i){
        u = read(),v = read(),w = read();
        add(u,v,w),add(v,u,w);
    }
}
il int prim()
{
	for(re int i = 2;i <= n; ++i) dis[i] = inf;
	for(re int i = head[1];i;i = e[i].next){
	  dis[e[i].v] = min(dis[e[i].v],e[i].w);
	}
    while(++tot<n){
        re int minn = inf;
        vis[now] = 1;
        for(re int i = 1;i <= n;++i){
            if(!vis[i]&&minn > dis[i]){
                minn = dis[i];
	        now = i;
            }
        }
        ans += minn;
        for(re int i = head[now];i;i = e[i].next){
        	re int v = e[i].v;
        	if(dis[v] > e[i].w&&!vis[v]){
        		dis[v] = e[i].w;
        	}
	 }
    }
    return ans;
}
int main(){
    init();
    printf("%d",prim());
    return 0;
}

Kruskal

选取权值较小的边,并依次连接,若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可

/*
work by:Ariel
*/
#include<iostream>
#include<cstdio>
#include<queue> 
#include <algorithm>
using namespace std;
const int  M = 500010;
int read(){
	int f = 1,x = 0;char c = getchar();
	while(c < '0'||c > '9'){if(c == '-')f = -1,c = getchar();}
	while(c <= '9'&&c >= '0'){x = x*10 + c - '0',c = getchar();}
	return f*x;
}

struct edge{
	int u,v,w;
}e[M];
int n,m,fa[M];
int find(int x){
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}
int cmp(edge x,edge y){
	return x.w < y.w;
}
int pd(int x,int y){//判断x,y是否在图上 
    int a = find(x);
    int b = find(y);
    if(a != b){
       fa[b] = a;
       return 1;
	}
	return 0;
}
int main()
{
	n = read(),m = read();
	for (int i = 1;i <= m; i++){
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	}
    int cnt = 0,ans = 0;
    sort(e + 1,e + m + 1,cmp);
	for (int i =1 ;i <= n; i++)
		fa[i] = i;   
	for (int i = 1;i <= m; i++){
	    if (pd(e[i].u,e[i].v) == 1){
	    	 cnt ++;
	    	 ans += e[i].w; 
		}
	    if(cnt == n-1) break;
	}
	if(cnt == n-1) printf("%d",ans);
	else printf("orz");
	return 0;
}
原文地址:https://www.cnblogs.com/Arielzz/p/14290008.html