zoukankan      html  css  js  c++  java
  • 最小生成树核心Algorithm(C++)

    最小生成树核心Algorithm

    问题描述:给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环,边权可能为负数。

    求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

    给定一张边带权的无向图 G=(V,E),其中 V 表示图中点的集合,E 表示图中边的集合,n=|V|,m=|E|。

    由 V 中的全部 n 个顶点和 E中 n−1 条边构成的无向连通子图被称为 G 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。

    输入格式

    第一行包含两个整数 n 和 m。

    接下来 m 行,每行包含三个整数 u,v,w表示点 u 和点 v 之间存在一条权值为 w 的边。

    输出格式

    共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

    数据范围

    1≤n≤10^5, 1≤m≤2∗10^5, 图中涉及边的边权的绝对值均不超过 1000。

    输入样例:

     4 5
     1 2 1
     1 3 2
     1 4 3
     2 3 2
     3 4 4

    输出样例:

     6

    Prim Algorithm

    code:

     #include<cstdio>
     #include<cstring>
     #include<iostream>
     #include<algorithm>
     using namespace std;
     
     const int N = 510,INF = 0x3f3f3f3f;
     int g[N][N],dist[N];
     bool st[N];
     int n,m;
     
     int prim(){
         //初始化点到生成树集合的距离为∞
         memset(dist,0x3f,sizeof dist);
         
         int res = 0;
         //迭代n次后n个点就全部加入到最小生成树中了
         for(int i=0;i<n;i++){
             int t = -1;
             //每次找到到集合距离最短的点,
             for(int j=1;j<=n;j++){
                 if(!st[j]&&(t==-1||dist[t]>dist[j]))
                     t = j;
            }
             //如果i不是第一个点,且所有点中dist最小为INF,说明该图不连通,就说明最小生成树不存在,就返回INF
             if(i&&dist[t]==INF) return INF;
             
             //先加入、再更新!!!!!!!!,否则如果存在负权自环,那么他会把它自身先更新了,会影响结果。
             if(i) res += dist[t];
             for(int j=1;j<=n;j++) dist[j] = min(dist[j],g[t][j]);
             
             
             st[t] = true;
        }
         
         return res;
     }
     int main(){
         scanf("%d%d",&n,&m);
         memset(g,0x3f,sizeof g);
         while(m--){
             int a,b,c;
             scanf("%d%d%d",&a,&b,&c);
             g[a][b] = g[b][a] = min(g[a][b],c);
        }
         
         int t = prim();
         if(t==INF) puts("impossible");
         else printf("%d ",t);
         return 0;
     }

    Kruskal Algorithm

    code:

     #include<cstdio>
     #include<cstring>
     #include<iostream>
     #include<algorithm>
     using namespace std;
     
     const int N = 2e5 + 10;
     int p[N];
     struct Edge{
         int a,b,w;
         
         //重载<运算符,方便下文中排序
         bool operator<(const Edge &e)const {
             return w<e.w;
        }
     }edge[N];
     
     int find(int x){//并查集模板
         if(x != p[x]) p[x] = find(p[x]);
         return p[x];
     }
     
     int main(){
         int n,m;
         scanf("%d%d",&n,&m);
         for(int i=0;i<m;i++){
             int a,b,c;
             scanf("%d%d%d",&a,&b,&c);
             edge[i] = {a,b,c};
        }
         
         sort(edge,edge+m);
         for(int i=1;i<=n;i++) p[i] = i;//并查集初始化
         int res = 0;//最小生成树的权值和,初始化为0
         int cnt = 0;//已经在生成树中的边,要想成为最小生成树,最基本的条件是当cnt==边数-1
         for(int i=0;i<m;i++){
             int a = edge[i].a,b = edge[i].b,w = edge[i].w;
             int fa = find(a),fb = find(b);
             if(fa != fb){//凡是两栖边 就将两点连入最小生成树
                 res += w;
                 cnt++;
                 p[fa] = fb;
            }
        }
         
         if(cnt < n-1) puts("impossible");
         else printf("%d ",res);
         return 0;
     }

     

  • 相关阅读:
    UVa 12174 (滑动窗口) Shuffle
    UVa 1607 (二分) Gates
    CodeForces ZeptoLab Code Rush 2015
    HDU 1525 (博弈) Euclid's Game
    HDU 2147 (博弈) kiki's game
    UVa 11093 Just Finish it up
    UVa 10954 (Huffman 优先队列) Add All
    CodeForces Round #298 Div.2
    UVa 12627 (递归 计数 找规律) Erratic Expansion
    UVa 714 (二分) Copying Books
  • 原文地址:https://www.cnblogs.com/yuanshixiao/p/14815234.html
Copyright © 2011-2022 走看看