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

    首先求出最小生成树,我们枚举每条不在最小生成树上的边,并把这条边放到最小生成树上面,然后就一定会形成环,那么我们在这条环路中取出一条最长的路(除了新加入的那一条边)。最终我们得到的权值就是次小生成树的权值。

    prim算法实现:

    我们在求解次小生成树的时候我们要使用一个二维数组maxd[i][j]表示最小生成树中i点到j点的最远距离,我们使用动态规划的思想来计算这个数组,比如当前节点为x,他的父亲节点为per[x],以及根节点root,那么 maxd[root][x] = max(maxd[root][per[x]] , maxd[per[x]][x]);

    Kruskal算法实现:

    kruskla算法中我们枚举的边权值会依次增大,那么就会给我们计算提供一定的便利,但是因为kruskal的实现方式和prim有所不同,所以kruskal需要存储当前最小生成树中的节点,然后我们再去更新maxd数组。

    prim:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cstdio>
     5 #define INF 0x3f3f3f3f
     6  
     7 using namespace std;
     8 const int MAXN = 110;
     9 int n,m,mapp[MAXN][MAXN];
    10 bool vis[MAXN],connect[MAXN][MAXN];
    11 int dis[MAXN],maxd[MAXN][MAXN],per[MAXN];
    12 void Init()
    13 {
    14     memset(mapp,INF,sizeof(mapp));
    15     memset(connect,false,sizeof(connect));
    16 }
    17 int prim()
    18 {
    19     memset(maxd,0,sizeof(maxd));
    20     memset(vis,false,sizeof(vis));
    21     for(int i = 1;i <= n;i ++)
    22     {
    23         dis[i] = mapp[1][i];per[i] = 1;//首先父亲节点都是根节点
    24     }
    25     vis[1] = 1;
    26     dis[1] = 0;
    27     int res = 0;
    28     for(int i = 1;i < n;i ++)
    29     {
    30         int index = -1,temp  = INF;
    31         for(int j = 1;j <= n;j ++)
    32             if(!vis[j] && dis[j] < temp)
    33             {
    34                 index = j;temp = dis[j];
    35             }
    36         if(index == -1) return res;
    37         vis[index] = 1;
    38         connect[index][per[index]] = false;connect[per[index]][index] = false;//这条边已经在最小生成树中,后面我们就不能添加这条边了
    39         res += temp;
    40         maxd[per[index]][index] =maxd[index][per[index]] =  temp;//更新点之间的最大值
    41         for(int j = 1;j <= n;j ++)
    42         {
    43             if(j != index && vis[j])//只是更新我们已经遍历过来的节点
    44             {
    45                 maxd[index][j] = maxd[j][index] = max(maxd[j][per[index]],dis[index]);
    46             }
    47             if(!vis[j] && mapp[index][j] < dis[j])
    48             {
    49                 dis[j] = mapp[index][j];
    50                 per[j] = index;
    51             }
    52         }
    53     }
    54     return res;
    55 }
    56 int main()
    57 {
    58     int T;
    59     scanf("%d
    ",&T);
    60     while(T--)
    61     {
    62         scanf("%d%d",&n,&m);
    63         Init();
    64         int u,v,w;
    65         for(int i = 0;i < m;i ++)
    66         {
    67             scanf("%d%d%d",&u,&v,&w);
    68             mapp[u][v] = w;mapp[v][u]  = w;
    69             connect[u][v] = true;connect[v][u] = true;
    70         }
    71         int ans = prim();
    72         bool over = false;
    73         //如果有某条边没有被最小生成树使用,并且i~j的最大值大于图中得到最大值,那么就表示次小生成树存在
    74         //相反就不会存在
    75          for(int i = 1;!over && i <= n;i ++)
    76             for(int j = 1;j <= n;j ++)
    77             {
    78                 if(connect[i][j] == false || mapp[i][j] == INF)
    79                     continue;
    80                 if(mapp[i][j] == maxd[i][j])//当边长度相同是就是表示最小生成树相同
    81                 {
    82                     over = 1;
    83                     break;
    84                 }
    85             }
    86         if(over)
    87             printf("Not Unique!
    ");
    88         else
    89             printf("%d
    ",ans);
    90     }
    91      //如果我们需要求解次小生成树的权值时,我们就要把在最小生成树中没有用过的边,加上然后减去对应环中最大的路径
    92      return 0;
    93 }

    kruskal:

     1 #include <vector>
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 #define INF 0x3f3f3f3f
     7  
     8 using namespace std;
     9 int n,m;
    10 struct data
    11 {
    12     int u,v,w;
    13     bool vis;
    14 } p[20010];
    15 vector<int>G[110];
    16 int per[110],maxd[110][110];
    17 bool cmp(data a,data b)
    18 {
    19     return a.w < b.w;
    20 }
    21 int Union_Find(int x)
    22 {
    23     return x == per[x] ? x: per[x] = Union_Find(per[x]);
    24 }
    25 void kruskal()
    26 {
    27     sort(p,p+m,cmp);
    28     for(int i=0; i<=n; i++)//初始化
    29     {
    30         G[i].clear();
    31         G[i].push_back(i);
    32         per[i]=i;
    33     }
    34     int sum=0,k=0;//sum是最小生成树的值
    35     for(int i=0; i<m; i++)
    36     {
    37         if(k==n-1)  break;
    38         int x1=Union_Find(p[i].u),x2=Union_Find(p[i].v);
    39         if(x1!=x2)
    40         {
    41             k++;
    42             p[i].vis=1;//这条边已经用过了
    43             sum+=p[i].w;
    44             int len_x1=G[x1].size();
    45             int len_x2=G[x2].size();
    46             for(int j=0; j<len_x1; j++)//更新两点之间距离的最大值
    47                 for(int k=0; k<len_x2; k++)
    48                     maxd[G[x1][j]][G[x2][k]]=maxd[G[x2][k]][G[x1][j]]=p[i].w;//因为后面的边会越来越大,所以这里可以直接等于当前边的长度
    49             per[x1]=x2;
    50             //因为per[x1] = x2,在Union_Find函数中要寻找和x1相关联节点的跟节点的时候,都会找到x2,所以这里不用再去更新和x1节点相连的节点
    51             //十分感谢Self-Discipline博主,提出此问题
    52 //            int tem[110];
    53 //            for(int j=0; j<len_x2; j++)//现在已经属于一棵树了,那么我们就将点添加到相应的集合中
    54 //                tem[j]=G[x2][j];
    55             for(int j=0; j<len_x1; j++)
    56                 G[x2].push_back(G[x1][j]);
    57 //            for(int j=0; j<len_x2; j++)
    58 //                G[x1].push_back(tem[j]);
    59         }
    60     }
    61     int cisum=INF;//次小生成树的权值
    62     for(int i=0; i<m; i++)
    63         if(!p[i].vis)
    64             cisum=min(cisum,sum+p[i].w-maxd[p[i].u][p[i].v]);
    65     if(cisum>sum)
    66         printf("%d
    ",sum);
    67     else
    68         printf("Not Unique!
    ");
    69 }
    70 int main()
    71 {
    72     int T;
    73     scanf("%d
    ",&T);
    74     while(T--)
    75     {
    76         scanf("%d%d",&n,&m);
    77         for(int i=0; i<m; i++)
    78         {
    79             scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
    80             p[i].vis = false;
    81         }
    82         kruskal();
    83     }
    84     return 0;
    85 }
  • 相关阅读:
    微信网页授权功能来获取用户信息(昵称或头像)之php实现
    你人生的那口井挖好了吗?
    java项目打jar包
    Oracle 客户端配置笔记
    资源管理右键卡住的问题
    Java Web 项目学习(二) 开发注册功能
    Java Web 项目学习(三) 过滤敏感词 前缀树 反射 类加载
    Java Web 项目学习(二) 检查登录状态
    Java Web 项目学习(二)账号设置
    Java Web 项目学习(二) 显示登录信息
  • 原文地址:https://www.cnblogs.com/St-Lovaer/p/11827875.html
Copyright © 2011-2022 走看看