题目链接
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);
}
}