就是求最小生成树是否唯一。
先求最小生成树,标记经过的边。再依次以未标记的边为起点,用Kruskal算法求最小生成树,若某个结果跟原来一样,则最小生成树不唯一。
下面是代码。
int N,M;
//边
struct edge{
int from,to;
int value;//权值
int used;//标记是否用过
void init(int from,int to,int value){//初始化
this->from=from;this->to=to;this->value=value;used=0;
}
bool operator <(const edge&b)const{//重载小于,便于排序
return value<b.value;
}
}edges[5000];
int En;//边数
//并查
struct node{
int parent;
void init(int i){
parent=i;
}
}nodes[100];
int find(int x){
int r=x;
while(r!=nodes[r].parent){
r=nodes[r].parent;
}
return nodes[x].parent=r;
}
//Kruskal算法
int Kruskal(int T){//T若为-1,表示第一次使用,需将用过的边标记,若不为-1,则表示以标号为T的边为起点
for(int i=0;i<N;i++) nodes[i].init(i);//初始化并查集
int ANS=0;
// 若T不为-1,则表示以标号为T的边为起点
if(~T) nodes[edges[T].from].parent=edges[T].to,ANS+=edges[T].value;
for(int i=0;i<En;i++){
int a=find(edges[i].from),b=find(edges[i].to);
if(a==b) continue;//在一个集合,忽略这条边
nodes[a].parent=b;//连接a,b节点
ANS+=edges[i].value;
if(T==-1) edges[i].used=1;//若T为-1,标记使用的边
}
return ANS;
}
int main(void)
{
int T;cin>>T;
while(T--){
scanf("%d%d",&N,&M);
//建边
En=0;
for(int i=0;i<M;i++){
int v1,v2,value;
scanf("%d%d%d",&v1,&v2,&value);
edges[En++].init(v1-1,v2-1,value);
}
//排序
sort(edges,edges+En);
//求初始答案
int ANS=Kruskal(-1);
//依次以未标记边为起点
int _ANS;int Unique=1;
for(int i=0;i<En;i++){//搜索所有的边
if(!edges[i].used){//若未标记
_ANS=Kruskal(i);//将之作为起点用Kruskal算法
if(_ANS==ANS){//如果结果相同,表明不唯一
printf("Not Unique!\n");
Unique=0;
break;
}
}
}
if(Unique) cout<<ANS<<endl;//如果唯一,输出结果
}
return 0;
}