Fork me on GitHub

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

 

posted @ 2014-04-03 20:36  whatbeg  阅读(300)  评论(0编辑  收藏  举报