URAL 1416 Confidential --最小生成树与次小生成树

题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1

解法:用Kruskal求最小生成树,标记用过的边。求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就是次小的生成树。可以证明:最小生成树与次小生成树之间仅有一条边不同。不过这样复杂度有点高,可达O(m^2).

求次小生成树有O(mlogm+n^2)的算法,详见

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#define Mod 1000000007

using namespace std;

#define N 507



struct Edge

{

    int s,t,w;

}edge[N*N];



int fa[N],use[N],n,m,minedge;  //minedge:最小生成树的边数



void init()

{

    for(int i=1;i<=n;i++)

        fa[i] = i;

}



int cmp(Edge ka,Edge kb)

{

    return ka.w < kb.w;

}



int findset(int x)

{

    if(x != fa[x])

        fa[x] = findset(fa[x]);

    return fa[x];

}



int Kruskal_MinTree()

{

    int u,v;

    init();

    int i,flag,cnt;

    minedge = 0;

    flag = cnt = 0;

    int tmp = 0;

    for(i=0;i<m;i++)

    {

        u = edge[i].s;

        v = edge[i].t;

        int fx = findset(u);

        int fy = findset(v);

        if(fx != fy)

        {

            use[minedge++] = i;

            tmp += edge[i].w;

            fa[fx] = fy;

            cnt++;

        }

        if(cnt == n-1)

        {

            flag = 1;   //找到最小生成树

            break;

        }

    }

    if(flag)

        return tmp;

    return -1;   //不存在最小生成树,返回-1

}



int Sec_MinTree()

{

    int i,j,mini,tmp;

    int cnt,flag,u,v;

    mini = Mod;

    for(i=0;i<minedge;i++)   //枚举最小生成树中的每条边,将其去除

    {

        init();

        flag = cnt = tmp = 0;

        for(j=0;j<m;j++)

        {

            if(j != use[i])  //去除边

            {

                u = edge[j].s;

                v = edge[j].t;

                int fx = findset(u);

                int fy = findset(v);

                if(fx != fy)

                {

                    cnt++;

                    tmp += edge[j].w;

                    fa[fx] = fy;

                }

                if(cnt == n-1)

                {

                    flag = 1;

                    break;

                }

            }

        }

        if(flag && tmp < mini)

            mini = tmp;

    }

    if(mini == Mod)

        mini = -1;

    return mini;

}



int main()

{

    int i,j;

    int u,v,w;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(i=0;i<m;i++)

        {

            scanf("%d%d%d",&u,&v,&w);

            edge[i].s = u;

            edge[i].t = v;

            edge[i].w = w;

        }

        sort(edge,edge+m,cmp);

        int flag = Kruskal_MinTree();

        int mini = Sec_MinTree();

        printf("Cost: %d\n",flag);

        printf("Cost: %d\n",mini);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(最小生成树)