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

    简介:在无向图中,连通且不含圈的图称为树;

             给定无向图G=(V,E),连接G中的所有点,且边集是E的子集的树称为G的生成树;

             而权值最小的生成树称为最小生成树(MST)

    • 两种常见的方法:

    1.Prim算法

    图例说明不可选可选已选(Vnew
     

    此为原始的加权连通图。每条边一侧的数字代表其权值。 - - -

    顶点D被任意选为起始点。顶点ABEF通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。 C, G A, B, E, F D
     

    下一个顶点为距离DA最近的顶点。BD为9,距A为7,E为15,F为6。因此,FDA最近,因此将顶点F与相应边DF以高亮表示。 C, G B, E, F A, D
    算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。 C B, E, G A, D, F
     

    在当前情况下,可以在CEG间进行选择。CB为8,EB为7,GF为11。E最近,因此将顶点E与相应边BE高亮表示。 C, E, G A, D, F, B
     

    这里,可供选择的顶点只有CGCE为5,GE为9,故选取C,并与边EC一同高亮表示。 C, G A, D, F, B, E

    顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG G A, D, F, B, E, C

    现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。 A, D, F, B, E, C, G
    • 思路简述:首先,定义顶点集合V和边集合E(初始化都是空集)然后找到一个起点,再在集合中找到所有与该点直接相连的点,找到边权最小的,收入记录最小生成树的集合。以此类推,直到所有定点都被记录在最小生成树中。
    • 例题:
    Agri-Net
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 58599   Accepted: 24300

    Description

    Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.  Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.  Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.  The distance between any two farms will not exceed 100,000. 

    Input

    The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.

    Output

    For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.

    Sample Input

    4
    0 4 9 21
    4 0 8 17
    9 8 0 16
    21 17 16 0
    

    Sample Output

    28

    Source

     
     1 #include <iostream>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <cstdlib>
     6 #include <algorithm>
     7 #define MAXN 1010101
     8 using namespace std;
     9 int map[501][501];  //map是边集 
    10 int low[10101];  //每个点到当前pos的最短边 
    11 bool vis[10101];  //记录当前位置是否被访问过 
    12 int n;
    13 int ans;
    14 void prim(int pos)
    15 {
    16     ans=0;  //
    17     memset(vis,0,sizeof(vis));  //这两行的初始化很重要 
    18     vis[pos]=1;
    19     for(int i=1;i<=n;i++)
    20         if(i!=pos) low[i]=map[pos][i];  //在每组数据的最开始初始化所有点到pos=1的距离 
    21     for(int i=1;i<n;i++) //把未纳入最小生成树的点都遍历一遍 
    22     {
    23         int minn=MAXN;
    24         for(int j=1;j<=n;j++)
    25             if(vis[j]==0 && low[j]<minn) //找最小距离 
    26             {
    27                 minn=low[j];
    28                 pos=j;
    29             }
    30         vis[pos]=1;
    31         ans+=minn; //更新结果 
    32         for(int j=1;j<=n;j++)  //更新权值 
    33             if(vis[j]==0 && low[j]>map[pos][j])
    34                 low[j]=map[pos][j];
    35     }
    36 }
    37 
    38 int main()
    39 {
    40     while(cin>>n)
    41     {
    42         memset(map,MAXN,sizeof(map));
    43         for(int i=1;i<=n;i++)
    44             for(int j=1;j<=n;j++)
    45             {
    46                 int x;
    47                 scanf("%d",&x);
    48                 map[i][j]=map[j][i]=x;
    49             }
    50         prim(1);
    51         printf("%d
    ",ans);
    52     }
    53     //system("pause");
    54     return 0;
    55 }
    POJ 1258

    2.Kruskal 算法

    首先第一步,我们有一张图Graph,有若干点和边 

    将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资                            源进行选择,排序完成后,我们率先选择了边AD。这样我们的图就变成了左图

    在剩下的边中寻找。我们找到了CE。这里边的权重也是5

    依次类推我们找到了6,7,7,即DF,AB,BE。(在找到AB和BE时,发现他们两端的顶点不属于同一个连通分量,因此加上了这                            两条边)

    下面继续选择, BC或者EF尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连                            接,类似的EF可以通过EB,BA,AD,DF来接连)。所以不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示                            了)。

                               最后就剩下EG和FG了。当然我们选择了EG。最后成功的图就是左图。

     

    •  思路简述:先把边按权排序,之后依次判断每条边的两个顶点是否属于同一个联通分量(即一个连通子图)。若属于,这条边就不应加上,因为会形成一个环,说明这条边是多余的;若不属于,就应加上。实现的重点是判断,因此要用到并查集。实现起来很便捷,且数量级近似于常数级。
    • 例题:

    Bad Cowtractors

    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 15278   Accepted: 6276

     

    Description

    Bessie has been hired to build a cheap internet network among Farmer John's N (2 <= N <= 1,000) barns that are conveniently numbered 1..N. FJ has already done some surveying, and found M (1 <= M <= 20,000) possible connection routes between pairs of barns.  Each possible connection route has an associated cost C (1 <= C <= 100,000).  Farmer John wants to spend the least amount on connecting the network; he doesn't even want to pay Bessie.
    Realizing Farmer John will not pay her, Bessie decides to do the worst job possible.  She must decide on a set of connections to install so that (i) the total cost of these connections is as large as possible, (ii) all the barns are connected together (so that it is possible to reach any barn from any other barn via a path of installed connections), and (iii) so that there are no cycles among the connections (which Farmer John would easily be able to detect). Conditions (ii) and (iii) ensure that the final set of connections will look like a "tree".

    Input

    * Line 1: Two space-separated integers: N and M
    * Lines 2..M+1: Each line contains three space-separated integers A, B, and C that describe a connection route between barns A and B of cost C.

    Output

    * Line 1: A single integer, containing the price of the most expensive tree connecting all the barns.  If it is not possible to connect all the barns, output -1.

    Sample Input

    5 8
    1 2 3
    1 3 7
    2 3 10
    2 4 4
    2 5 8
    3 4 6
    3 5 2
    4 5 17

    Sample Output

    42

    Hint

    OUTPUT DETAILS:
    The most expensive tree has cost 17 + 8 + 10 + 7 = 42.  It uses the following connections: 4 to 5, 2 to 5, 2 to 3, and 1 to 3.

    Source

     
     1 #include <iostream>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <cstdlib>
     6 #include <algorithm>
     7 #define MAXN 20101
     8 using namespace std;
     9 int n,m;
    10 int u[MAXN],v[MAXN],c[101010];
    11 int p[1010],r[MAXN];
    12 int num=1;  //记录能否包含所有点,初始化即为一个点 
    13 int cmp(const int i,const int j) {return c[i]>c[j];}  //从大到小排序 
    14 int find(int x) {return p[x] == x ? x : p[x]=find(p[x]);}  //找祖先 
    15 int kruskal()
    16 {
    17     int sum=0;
    18     for(int i=1;i<=m;i++)
    19     {
    20         int e=r[i];
    21         int x=find(u[e]),y=find(v[e]);  //判断他两端的顶点是否属于一个连通分量 
    22         if(x!=y)
    23         {
    24             sum+=c[e];
    25             p[x]=y;
    26             num++;
    27         }
    28     }
    29     return sum;
    30 }
    31 
    32 int main()
    33 {
    34     scanf("%d%d",&n,&m);
    35     for(int i=1;i<=m;i++)
    36         scanf("%d%d%d",&u[i],&v[i],&c[i]);
    37     for(int i=1;i<=n;i++) p[i]=i; //初始化 
    38     for(int i=1;i<=m;i++) r[i]=i;
    39     sort(r+1,r+m+1,cmp);  
    40     int ans=kruskal();
    41     if(num<n) printf("-1");
    42     else printf("%d",ans);
    43     //system("pause");
    44     return 0;
    45 }
    POJ 2377

     特别注意:代码里的u,v数组记录的是每条边两端的点,而不是点的个数!!!所以这两个数组的范围应该是边m的范围。

  • 相关阅读:
    linux上用selenium登录新浪微博,获取用户关注的用户id
    JS、Python对字符串的编码函数
    在ubuntu系统下装hadoop
    windows下python3.x的安装与使用
    python多线程、多进程、协程的使用
    python简单操作redis
    操作系统基础知识
    排序算法汇总
    网易的突然袭击
    小红书视频面试
  • 原文地址:https://www.cnblogs.com/YXY-1211/p/7154203.html
Copyright © 2011-2022 走看看