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

来源:互联网 发布:英语四级网络课程 编辑:程序博客网 时间:2024/05/18 13:05

题目链接

http://poj.org/problem?id=1679

题意:

判断最小生成树是否唯一

思路:

首先生成一颗最小生成树,然后枚举每条不在生成树里的边(i,j),将其加入生成树中,此时会成环,再去掉生成树里I到j间最大的边,这样可以得到另一个生成树。因为在最小生成树中,最大的边是所有生成树中最小的。这样替换后如果可以生成一个一样生成树,那么最小生成树就不是唯一的。

#include<cstdio>//最小生成树最大的边,是所有生成树中,最大边最小的。 #include<queue> //同理,第二大的边也是最小的。 #include<iostream>#include<vector>#include<map>#include<cstring>#include<string>#include<set>#include<stack>#include<algorithm>#define cle(a) memset(a,0,sizeof(a))#define inf(a) memset(a,0x3f,sizeof(a))#define ll long long#define Rep(i,a,n) for(int i=a;i<=n;i++)using namespace std;const int INF = ( 2e9 ) + 2;const ll maxn =110;int lowcost[maxn],vis[maxn];int c[maxn][maxn],used[maxn][maxn],pre[maxn],max1[maxn][maxn]; // max1[i][j] 代表i到j间的最大的边 pair<int,int> prim(int n){    int ret=0;    for(int i=1;i<=n;i++)    {        lowcost[i]=c[1][i];        pre[i]=1;    }    memset(used,0,sizeof(used));    memset(max1,0,sizeof(max1));    memset(vis,0,sizeof(vis));    vis[1]=1;    for(int i=2;i<=n;i++)    {        int mn=INF;        int pos=-1;        for(int k=2;k<=n;k++)            if(!vis[k]&&mn>lowcost[k])            {                mn=lowcost[k];                pos=k;            }        if(mn==INF)return make_pair(0,0);        ret+=mn;        vis[pos]=1;        used[pre[pos]][pos]=used[pos][pre[pos]]=1;        for(int k=1;k<=n;k++)        {            if(vis[k])            max1[k][pos]=max1[pos][k]=max(max1[k][pre[pos]],mn);            if(!vis[k]&&c[pos][k]<lowcost[k])            {                lowcost[k]=c[pos][k];                pre[k]=pos;            }        }    }    return make_pair(1,ret);}int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,m;        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)        c[i][j]=INF+1;        for(int i=0;i<m;i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            c[u][v]=w;            c[v][u]=w;        }        pair<int,int> ans=prim(n);        if(ans.first==0)        printf("Not Unique!\n");        else        {            int f=INF;            for(int i=1;i<=n;i++)            for(int j=i+1;j<=n;j++)            {                if(!used[i][j]&&c[i][j]!=INF+1)                {                    f=min(f,c[i][j]-max1[i][j]);                }            }            if(f==0)            printf("Not Unique!\n");            else            printf("%d\n",ans.second);        }    }}

思路2:

先预处理边,判断是否有权值相等的边,用kruscal算法算出最小生成树,并记录哪些边加入了最小生成树中。试着将加入最小生成树的边,且存在有权值与其相等的边,将其删除,重新构造最小生成树,如果出现相同的,那么说明不唯一。

#include<cstdio>#include<queue>#include<iostream>#include<vector>#include<map>#include<cstring>#include<string>#include<set>#include<stack>#include<algorithm>#define cle(a) memset(a,0,sizeof(a))#define inf(a) memset(a,0x3f,sizeof(a))#define ll long long#define Rep(i,a,n) for(int i=a;i<=n;i++)using namespace std;const int INF = ( 2e9 ) + 2;const ll maxn = 110;int f[maxn],del[maxn*maxn],used[maxn*maxn],equ[maxn*maxn];int first;struct edge{    int u,v,w;};vector<edge> e;bool cmp(edge a,edge b){    return a.w<b.w;}int Find(int x){    return f[x]==x?x:f[x]=Find(f[x]);}int Kruscal(int n){    for(int i=1;i<=n;i++)f[i]=i;    int ret=0;    for(int i=0;i<e.size();i++)    {        int u=e[i].u,v=e[i].v,w=e[i].w;        if(del[i])continue;        int xx=Find(u);        int yy=Find(v);        if(xx!=yy)        {            f[xx]=yy;            if(first)            used[i]=1;            ret+=w;        }    }    return ret;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,m;        e.clear();        scanf("%d%d",&n,&m);        for(int i=0;i<m;i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            e.push_back(edge{u,v,w});        }        sort(e.begin(),e.end(),cmp);        memset(equ,0,sizeof(equ));        memset(used,0,sizeof(used));        memset(del,0,sizeof(del));        for(int i=1;i<e.size();i++)        {            if(e[i-1].w==e[i].w)equ[i-1]=1,equ[i]=1;        }        first=1;        int w1=Kruscal(n);        first=0;        int unique=1;        for(int i=0;i<e.size();i++)        {            if(equ[i]&&used[i])            {                del[i]=1;                int temp=Kruscal(n);                del[i]=0;                if(temp==w1)                {                    printf("Not Unique!\n");                    unique=0;                    break;                }            }        }        if(unique)        printf("%d\n",w1);    }}
阅读全文
0 0