码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 1679 The Unique MST 判断最小生成树是否唯一/次小生成树

时间:2015-01-26 11:59:52      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:c++   poj   

题目链接:

1679




题意:

给出 M个点N条边 求它的的最小生成树 不唯一则输出:Not Unique!




题解:

prim:判断“最小生成树是否唯一”可以理解为“最小生成树和次小生成树是否相等

求次小生成树的步骤如下

1)先求出最小生成树T,在prim的同时,用一个矩阵maxx[u][v]记录在树中连接u-v的路径中权值最大的边.
2)枚举所有不在T中的边map[u][v],加入边u-v,删除权值为maxx[u][v]的边;

3)找到MST-maxx[u][v]+map[u][v]的最小值即为次小生成树的值,而如果

maxx[u][v]==map[u][v]  则说明最小生成树和次小生成树相等.



kurskal:

通过kurskal算法标记最小生成树中的每条边 used=1,  然后每次删除一条(标记used==1且权值与其他边的相同的边)

再进行kruskal算法 如果求得的值==MST    则说明MST不唯一





prim代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define max1  0x3f3f3f3f
int lowdis[105];
int map[105][105];
int connect[105][105];       //标记所有不在生成树的边
int maxx[105][105];          //保存 u->v 的最大边
int pre[105];                
int m,ans;
void prim()
{
    int i,j,pree,loc,minn;
    for(i=1; i<=m; i++)
    {
        lowdis[i]=map[1][i];
        pre[i]=1;
    }
    lowdis[1]=-1;
    for(i=1; i<m; i++)
    {
        minn=max1;
        for(j=1; j<=m; j++)
            if(lowdis[j]!=-1&&lowdis[j]<minn)
                minn=lowdis[j],loc=j;
        ans+=lowdis[loc];
        
        pree=pre[loc];
        connect[pree][loc]=connect[loc][pree]=0;
        
        maxx[pree][loc]=lowdis[loc];   //
        for(j=1; j<=m; j++)                                      
            maxx[j][loc]=maxx[j][pree]>maxx[pree][loc]?maxx[j][pree]:maxx[pree][loc];
            
        lowdis[loc]=-1;
        for(j=1; j<=m; j++)
            if(lowdis[j]>map[loc][j])
                    lowdis[j]=map[loc][j],pre[j]=loc;
    }
    return;
}
int main()
{
    int t,i,j,a,b,c,n;
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        scanf("%d%d",&m,&n);
        memset(connect,0,sizeof(connect));
        memset(map,max1,sizeof(map));
        memset(maxx,0,sizeof(maxx));
        while(n--)
        {
            scanf("%d%d%d",&a,&b,&c);
            map[a][b]=map[b][a]=c;
            connect[a][b]=connect[b][a]=1;
        }
        prim();
        int t=0;
        for(i=1; i<=m; i++)
        {
            for(j=1; j<=m; j++)                 //枚举每一条不在生成树中的边
            {
                if(map[i][j]==max1||connect[i][j]==0)
                    continue;
                if(map[i][j]==maxx[i][j])             //如果要求次小生成树 min(ans+map[i][j]-maxx[i][j])即可
                {
                    t=1;
                    cout<<"Not Unique!"<<endl;
                    break;
                }
            }
            if(t==1)
                break;
        }
        if(t==0)
            cout<<ans<<endl;
    }
    return 0;
}





Kruskal代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
    int u,v,w;
    int delate,used,equall;
} edge[10005];
int fa[10005],m,s,flag;
int cmp(node a,node b)
{
    return a.w<b.w;
}
int find(int x)
{
    int t,d=x;
    while(fa[d]>=0)
        d=fa[d];
    while(x!=d)
    {
        t=fa[x];
        fa[x]=d;
        x=t;
    }
    return d;
}
int kruskal()
{
    memset(fa,-1,sizeof(fa));
    int ans=0,r1,r2,ss,nn=0,i;
    for(i=0; i<s; i++)
    {
        r1=find(edge[i].u);
        r2=find(edge[i].v);
        if(r1!=r2&&edge[i].delate==0)
        {
            if(!flag)
                edge[i].used=1;
            ss=fa[r1]+fa[r2];
            nn++;
            ans+=edge[i].w;
            if(fa[r1]<fa[r2])
                fa[r1]=ss,fa[r2]=r1;
            else
                fa[r1]=r2,fa[r2]=ss;
        }
        if(nn==m-1)
            return ans;
    }
    return 0;
}
int main()
{
    int t,i,j,n;
    int a,b,c;
    int ans1,ans2;
    scanf("%d",&t);
    while(t--)
    {
        flag=s=0;
        scanf("%d%d",&m,&n);
        while(n--)
        {
            scanf("%d%d%d",&a,&b,&c);
            edge[s].delate=edge[s].equall=edge[s].used=0;
            edge[s].u=a;
            edge[s].v=b;
            edge[s++].w=c;
        }
        for(i=0; i<s; i++)
            for(j=0; j<i; j++)
            {
                if(edge[i].w==edge[j].w)
                    edge[i].equall=edge[j].equall=1;
            }
        sort(edge,edge+s,cmp);
        ans1=kruskal();
        flag=1;
        a=0;
        for(i=0; i<s; i++)
        {
            if(edge[i].equall==1&&edge[i].used==1)
            {
                edge[i].delate=1;
                ans2=kruskal();
                if(ans1==ans2&&ans1!=0)
                {
                    a=1;
                    cout<<"Not Unique!"<<endl;
                    break;
                }
                edge[i].delate=0;
            }
        }
        if(a==0)
            cout<<ans1<<endl;
    }
    return 0;
}





POJ 1679 The Unique MST 判断最小生成树是否唯一/次小生成树

标签:c++   poj   

原文地址:http://blog.csdn.net/axuan_k/article/details/43149989

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!