大致说下题意:有多个case 给出n m , n代表点数,m代表边数,之后给出m条边,该图的最小生成树是不是唯一的。
主要做法就是先用prim求出最小生成树,尝试在加入一条生成树外的边,并删除一条在树内的边,若该操作后,得到的值和原来一样就说明生成树不唯一。
另外,要注意不联通的情况,这是也输出"Not Unique!"
附代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<memory>
using namespace std;
typedef long long ll;
#define clr(name,value) memset(name,value,sizeof(name))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int inf = 0x3f3f3f3f, maxn = 100100;
int n,m,t,ans;
int g[105][105],d[105],pre[105],Max[105][105];
bool vis[105],used[105][105];
bool prim(){
clr(vis,0);
clr(d,inf);
clr(pre,-1);
clr(used,0); //表示该边有没有被访问过
clr(Max,0);
d[1]=0;
pre[1]=0;
ans=0;
int i,j,k,minn;
for(i=1;i<=n;i++){
minn=inf;
for(j=1;j<=n;j++){
if(!vis[j]&&minn>d[j]){
k=j;
minn=d[j];
}
}
if(minn==inf)
return 1; //如果是非连通图 返回1
vis[k]=1;
used[k][pre[k]]=used[pre[k]][k]=1;
ans+=d[k];
for(j=1;j<=n;j++){
if(vis[j]) Max[k][j]=Max[j][k]=max(Max[j][pre[k]],d[k]);
//Max[j][k]表示从j到k的路径中最大的边,非常重要!
if(!vis[j]&&d[j]>g[k][j]){
d[j]=g[k][j];
pre[j]=k;
}
}
}
return 0;
}
int main()
{
//freopen("f:/in.txt","r",stdin);
int i,j,u,v,w;
scanf("%d",&t);
while(t--){
clr(g,inf);
g[0][1]=g[1][0]=0;
scanf("%d%d",&n,&m);
for(i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
if(g[u][v]>w)
g[u][v]=g[v][u]=w;
}
if(prim()){
puts("Not Unique!");
continue;
}
int Min=inf;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
if(i!=j&&!used[i][j]){
Min=min(Min,ans+g[i][j]-Max[i][pre[i]]);
}
}
if(Min==ans)
puts("Not Unique!");
else
printf("%d\n",ans);
}
return 0;
}
下面给出几组数据吧
3
5 6
1 2 1
1 5 2
2 5 3
2 3 2
3 4 6
2 4 4
答案:9
4 5
1 2 1
2 3 3
1 3 3
1 4 2
2 4 2
答案:Not Unique!
4 4
1 2 1
3 4 2
1 3 3
2 4 3
答案:Not Unique!
这组数据很有价值!正因为类似这种数据,才需要用到Max这个二维数组!!