zoukankan      html  css  js  c++  java
  • 最小生成树-Prim算法

    最小生成树minimal-spanning-tree(概念就不具体介绍了)有两种基于不同贪心选择的算法,一个为Prim算法,一个为Kruskal算法。

    Prim和Dijkstra算法很像,只是少了些东西。它将结点分为两类,一类是已经选择了的确定的,构建好了的mst的结点,另一类是还没确定的未选择的结点。

    流程是这样的:(括号内为权值),U集合:MST的点集合,V-U:未选择的点集合

    1.首先初始化开始结点U,然后把所有能够与U相连的边为候选边

    这里就是数组初始化操作了;

    1      int sum=0;
    2     for(int i=1;i<=n;i++)
    3     {
    4         dis[i]=map[1][i];//初始化所有点到结点1的距离
    5         vis[i]=false;//所有点开始都未被访问
    6     }
    7     vis[1]=true;//结点1标志为true

    1

    开始时U是结点1,然后找到所有与1相连的边(dist[i][j]!=0),分别是1-6(10),1-2(28),所以找出最小的(6<28)那个边对应的结点6加入集合U;

     1 for(int i=2;i<=n;i++)
     2     {
     3         int MIN=INF;//从当前节点u到与u联通的子节点的最小权值
     4         int k=-1;
     5         for(int j=1;j<=n;j++)//遍历每个点
     6         {
     7             if(!vis[j]&&dis[j]<MIN)//未被访问且距离还小,那就待定选你了,看看还有没有距离更短的
     8             {
     9                 MIN=dis[j];//更新最小值,这个dis表式这个点到已知mst中一点的最小值
    10                 k=j;//标记结点号
    11             }
    12         }
    13         vis[k]=true;//u->a->b  k->b //置已经访问
    14         sum+=MIN;//u->k求生成树的路径和
    15         ...
    16         ...
    17        ...
    18 }

    然后我们发现,左部分和右部分只有两条边相连了,那么继续找最短边就行6-5(25) <1-2(28),所以选择25的那条边,成这样

    再比较1-2(28),5-7(24),5-4(22),取出最小边是5-4(22),更新图

    继续比较选出最短边,这时有4个边要比较了,1-2(28),5-7(24),4-7(18),4-3(12),找出最短边4-3(12),更新图

    继续比较4个个边,1-2(28),5-7(24),4-7(18),3-2(16),找出最短的16,更新图

    好了,最后已给点7,应该很容易看出来它是2连接的,因为14是最短的。

    所以MST图是这样

    后半段的代码是这样的

    1 for(int j=1;j<=n;j++)//带已经找到点k的情况下,找结点j
    2         {
    3             if(!vis[j]&&dis[j]>map[k][j])
    4             {//j未访问且 j到mst中点的最小值还大于从k到j的距离,那么就   
    5 //要更新这段距离
    6                 dis[j]=map[k][j];//clost[j] = k;
    7             }
    8         }

    看这个图

    比如说开始先初始化,dist[6] =10;dist[4]=1,即结点6和4到结点1的最短距离为dist数组,然后我找到了最短路1-4,并且发现原来的1-6(10)大于6-4(5),所以更新dist[6]=4,他表示结点6到已知MST的某个点的最短的那个距离,也可以将那个点记录在clost数组中,以便需要。

    完整代码,其实很简单的

    邻接矩阵:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int INF=0x3f3f3f3f;
     6 const int MAXN=1005;
     7 int map[MAXN][MAXN];   //map[i][j]   ----  i->j =v
     8 int dis[MAXN];     //
     9 bool vis[MAXN];
    10 int n;
    11 void init()
    12 {
    13     for(int i=0;i<=n;i++)
    14     {
    15         for(int j=0;j<=n;j++)
    16         {
    17             if(i!=j)map[i][j]=INF;
    18             else map[i][j]=0;
    19         }
    20     }
    21 }
    22 int Prim()
    23 {
    24     int sum=0;
    25     for(int i=1;i<=n;i++)
    26     {
    27         dis[i]=map[1][i];
    28         vis[i]=false;
    29     }
    30     vis[1]=true;
    31     for(int i=2;i<=n;i++)
    32     {
    33         int MIN=INF;//从当前节点u到与u联通的子节点的最小权值
    34         int k=-1;//u->v k=v;
    35         for(int j=1;j<=n;j++)
    36         {
    37             if(!vis[j]&&dis[j]<MIN)
    38             {
    39                 MIN=dis[j];
    40                 k=j;
    41             }
    42         }
    43         vis[k]=true;//u->a->b  k->b
    44         sum+=MIN;//u->k
    45         for(int j=1;j<=n;j++)
    46         {
    47             if(!vis[j]&&dis[j]>map[k][j])
    48             {
    49                 dis[j]=map[k][j];
    50             }
    51         }
    52     }
    53     return sum;
    54 }
    55 int main()
    56 {
    57     cin>>n;
    58     init();
    59     for(int i=1;i<=n;i++)
    60     {
    61         for(int j=1;j<=n;j++)
    62         {
    63             int v;
    64             cin>>v;
    65             if(map[i][j]>v)
    66             {
    67                 map[i][j]=map[j][i]=v;
    68             }
    69         }
    70     }
    71     int c;
    72     cin>>c;
    73     for(int i=1;i<=c;i++)
    74     {
    75         int a,b;
    76         cin>>a>>b;
    77         map[a][b]=map[b][a]=0;
    78     }
    79     /*for(int i=1;i<=n;i++)
    80     {
    81         int a,b,v;
    82         cin>>a>>b>>v;
    83         /*if(map[a][b]>v)
    84         {
    85             map[a][b]=map[b][a]=v;
    86         }
    87         map[a][b]=v;
    88     }*/
    89     cout<<Prim()<<endl;
    90     return 0;
    91 }
    View Code

    邻接表:

      1 /*************************************************************************
      2     > File Name: p3366.cpp
      3     > Author: YeGuoSheng
      4     > Description: 
      5 最小生成树模板 、如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
      6 输入格式
      7 第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
      8 
      9 接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
     10 
     11 输出格式
     12 输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
     13 输入输出样例
     14 输入 #1 复制
     15 4 5
     16 1 2 2
     17 1 3 2
     18 1 4 3
     19 2 3 4
     20 3 4 3
     21 输出 #1 复制
     22 7
     23     > Created Time: 2019年08月02日 星期五 10时26分54秒
     24  ************************************************************************/
     25 
     26 #include<iostream>
     27 #include<stdio.h>
     28 #include<cstring>
     29 #include<cmath>
     30 #include<vector>
     31 #include<stack>
     32 #include<map>
     33 #include<set>
     34 #include<list>
     35 #include<queue>
     36 #include<string>
     37 #include<algorithm>
     38 #include<iomanip>
     39 using namespace std;
     40 const int maxn = 500005;
     41 const int INF = 0x3f3f3f3f;
     42 int head[maxn];
     43 int dis[maxn];
     44 int vis[maxn];
     45 int n,m;//顶点数,边数
     46 struct edge
     47 {
     48     int v;
     49     int w;
     50     int next;
     51 }edges[maxn<<1];
     52 
     53 int cnt = 1;
     54 
     55 void Add(int x,int y,int w)
     56 {
     57    edges[cnt].v = y;
     58    edges[cnt].w = w;
     59    edges[cnt].next = head[x];
     60    head[x] = cnt ++;
     61 }   
     62 
     63 void Init()
     64 {
     65     cin>>n>>m;
     66     int x,y,w;
     67     for(int i = 1;i <= m;i++)
     68     {
     69 
     70         cin>>x>>y>>w;
     71         Add(x,y,w);//添加双向边
     72         Add(y,x,w);
     73     }
     74 }
     75 
     76 void Prim()
     77 {
     78     int total = 0;
     79     int ans = 0;
     80     int now = 1;
     81     for(int i = 2;i <= n;i++)
     82     {
     83         dis[i] = INF;
     84     }
     85 
     86     for(int i = head[1];i;i=edges[i].next)
     87     {
     88         dis[edges[i].v] = min(dis[edges[i].v],edges[i].w);
     89     }//更新所有与起点1相连的边并找到最小值
     90 
     91     while(++total < n)//加入mst顶点数<图的顶点数即没找完,循环
     92     {
     93         int minn = INF;
     94         vis[now] = 1;
     95         for(int i = 1;i <= n;i++)
     96         {
     97             if (! vis[i] && minn > dis[i])//找到一条最短边
     98             {
     99                 minn = dis[i];
    100                 now = i;
    101             }
    102         }
    103         ans += minn;//当前找到的最短距离加入结果距离变量中
    104         for(int i = head[now]; i ; i =edges[i].next)//松弛操作
    105         {
    106             int v = edges[i].v;
    107             if(  ! vis[v]&& dis[v] > edges[i].w )
    108             {
    109                 dis[v] = edges[i].w;
    110             }
    111         }
    112     }
    113     if(ans < INF)//找到解
    114     {
    115        cout<<ans<<endl;
    116     }
    117     else
    118     {
    119         cout<<"orz"<<endl;
    120     }
    121     
    122 }
    123 int main()
    124 {
    125     Init();
    126     Prim();
    127     return 0;
    128 }
    View Code

    传送门:Agri-Net

  • 相关阅读:
    [LeetCode] Majority Element II
    [Nginx] 事件模型
    [Nginx] 进程模型
    [C++] 函数中的字符串指针与数组
    [LeetCode] Shortest Distance to a Character
    [LeetCode] Number of Lines To Write String
    Ubuntu 16.04中安装谷歌Chrome浏览器
    Python、机器学习、计算机视觉、深度学习入门
    Sublime安装与配置
    [20160807][系统设计的三次迭代]
  • 原文地址:https://www.cnblogs.com/ygsworld/p/11229055.html
Copyright © 2011-2022 走看看