zoukankan      html  css  js  c++  java
  • 最小生成树

    做题时发现自己只会打(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;
    }
    
  • 相关阅读:
    workerman定时器使用
    php foreach 传值还是传引用
    VPS技术介绍以及分析
    Xen、Openvz、KVM有什么区别?
    别说你会用 Google 搜索
    射手网字幕打包下载(73.16G)
    Windows Server 2003 激活码及激活方法
    Linux VPS 基本命令
    mysql 错误代码汇总
    SQL Server 2008 序列号
  • 原文地址:https://www.cnblogs.com/Arielzz/p/14290008.html
Copyright © 2011-2022 走看看