POJ 1679 【次小生成树】
题目链接:POJ 1679
题意:给出一个图,问其中的最小生成树是否唯一
题解:即比较最小生成树和次小生成树的值是否相同。
那么如何求次小生成树呢?
次小生成树一定是原最小生成树某一条边被禁用后求得的
思路:先跑一边最小生成树,然后分别测试禁用最小生成树中某一条边,重新求最小生成树,求得的最小结果即为次小生成树。
代码如下:
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int MAXN=105;
const int INF=0x3f3f3f3f;
int rankk[MAXN];
int par[MAXN];
void init(){
for(int i=0;i<MAXN;i++){
par[i]=i;
rankk[i]=0;
}
}
int findd(int x){
if(par[x]==x)return x;
else return par[x]=findd(par[x]);
}
void unite(int x,int y){
x=findd(x);
y=findd(y);
if(x==y)return;
if(rankk[x]>rankk[y]){
par[y]=x;
}
else{
par[x]=y;
if(rankk[x]==rankk[y])rankk[y]++;
}
}
bool same(int x,int y){
return findd(x)==findd(y);
}
struct edge{
int from,to,cost;
};
vector<edge> E;
bool comp(edge a,edge b){
return a.cost<b.cost;
}
int n,m;
vector<int> ine;
int kruskal(){
init();
int res=0;
for(int i=0;i<E.size();i++){
edge e=E[i];
if(!same(e.from,e.to)){
res+=e.cost;
unite(e.from,e.to);
ine.push_back(i);
}
}
return res;
}
int kruskals(int k){
init();
int res=0;
for(int i=0;i<E.size();i++){
if(i==k)continue;
edge e=E[i];
if(!same(e.from,e.to)){
res+=e.cost;
unite(e.from,e.to);
}
}
for(int i=2;i<=n;i++){
if(!same(1,i)){
return -1;
}
}
return res;
}
int main()
{
int num;
scanf("%d",&num);
while(num--){
scanf("%d%d",&n,&m);
int a,b,c;
edge e;
E.clear();
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
e.from=a;
e.to=b;
e.cost=c;
E.push_back(e);
}
sort(E.begin(),E.end(),comp);
ine.clear();
int mst=kruskal();
int cmst=0,flag=0;
for(int i=0;i<ine.size();i++){
cmst=kruskals(ine[i]);
if(cmst==mst){
flag=1;
break;
}
}
if(flag){
printf("Not Unique!\n");
}
else{
printf("%d\n",mst);
}
}
return 0;
}
求最小生成树使用的是kruskal算法(使用并查集结构判断两端点是否在同一个集合)