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

    这里只写Kruskal版本(太蒟了qwq)

    大致思路

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

    代码实现

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #define INF 0x3f3f3f3f
     
    using namespace std;
    const int MAXN = 110;
    int n,m,mapp[MAXN][MAXN];
    bool vis[MAXN],connect[MAXN][MAXN];
    int dis[MAXN],maxd[MAXN][MAXN],per[MAXN];
    void Init()
    {
        memset(mapp,INF,sizeof(mapp));
        memset(connect,false,sizeof(connect));
    }
    int prim()
    {
        memset(maxd,0,sizeof(maxd));
        memset(vis,false,sizeof(vis));
        for(int i = 1;i <= n;i ++)
        {
            dis[i] = mapp[1][i];per[i] = 1;//首先父亲节点都是根节点
        }
        vis[1] = 1;
        dis[1] = 0;
        int res = 0;
        for(int i = 1;i < n;i ++)
        {
            int index = -1,temp  = INF;
            for(int j = 1;j <= n;j ++)
                if(!vis[j] && dis[j] < temp)
                {
                    index = j;temp = dis[j];
                }
            if(index == -1) return res;
            vis[index] = 1;
            connect[index][per[index]] = false;connect[per[index]][index] = false;//这条边已经在最小生成树中,后面我们就不能添加这条边了
            res += temp;
            maxd[per[index]][index] =maxd[index][per[index]] =  temp;//更新点之间的最大值
            for(int j = 1;j <= n;j ++)
            {
                if(j != index && vis[j])//只是更新我们已经遍历过来的节点
                {
                    maxd[index][j] = maxd[j][index] = max(maxd[j][per[index]],dis[index]);
                }
                if(!vis[j] && mapp[index][j] < dis[j])
                {
                    dis[j] = mapp[index][j];
                    per[j] = index;
                }
            }
        }
        return res;
    }
    int main()
    {
        int T;
        scanf("%d
    ",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            Init();
            int u,v,w;
            for(int i = 0;i < m;i ++)
            {
                scanf("%d%d%d",&u,&v,&w);
                mapp[u][v] = w;mapp[v][u]  = w;
                connect[u][v] = true;connect[v][u] = true;
            }
            int ans = prim();
            bool over = false;
            //如果有某条边没有被最小生成树使用,并且i~j的最大值大于图中得到最大值,那么就表示次小生成树存在
            //相反就不会存在
             for(int i = 1;!over && i <= n;i ++)
                for(int j = 1;j <= n;j ++)
                {
                    if(connect[i][j] == false || mapp[i][j] == INF)
                        continue;
                    if(mapp[i][j] == maxd[i][j])//当边长度相同是就是表示最小生成树相同
                    {
                        over = 1;
                        break;
                    }
                }
            if(over)
                printf("Not Unique!
    ");
            else
                printf("%d
    ",ans);
        }
         //如果我们需要求解次小生成树的权值时,我们就要把在最小生成树中没有用过的边,加上然后减去对应环中最大的路径
         return 0;
    }
    

    代码出自https://blog.csdn.net/li1615882553/article/details/80011884
    手写版以后再说吧

  • 相关阅读:
    jq 京东跳楼效果
    *Sum of NestedInteger
    **Minimum Window Substring & String类问题模板
    **Word Ladder
    *Longest Increasing Subsequence
    *Kth Largest Element in an Array
    *Permutations II
    *Implement Stack using Queues
    *Paint House II
    *Paint Fence
  • 原文地址:https://www.cnblogs.com/whenc/p/13784588.html
Copyright © 2011-2022 走看看