The Unique MST - 最小生成树

Given a connected undirected graph, tell if its minimum spanning tree is unique. 

Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties: 
1. V' = V. 
2. T is connected and acyclic. 

Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E'. 
Input
The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.
Output
For each input, if the MST is unique, print the total cost of it, or otherwise print the string 'Not Unique!'.
Sample Input
2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2
Sample Output
3
Not Unique!

分析:

问是不是唯一的最小生成树,思路是建边的时候多加一个flag值,判断是不是MST的边,在选出来MST后,进行遍历,从MST的边中选一条边,去掉这条边后求MST,若这时的最短路径和以前相同则说明最小生成树不唯一。

注意啦,在去边,求最小生成树的时候,有可能求不出来,即去掉此边则没有最小生成树,这种情况也会出现的,边忘了判断。

代码如下:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105;
int pre[N];
int n,k;

struct proc{
    int from,to,cost,flag;
}edge[10003];

void addEdge(int a,int b,int c){
    edge[k].from=a;
    edge[k].to=b;
    edge[k++].cost=c;
}

int cmp(proc a,proc b){
    return a.cost<b.cost;
}

int f(int x){
    if(x==pre[x])return x;
    pre[x]=f(pre[x]);
    return pre[x];
}

int kruskal(int m,int ans){
    int sum=0,flag=0;
    for(int i=0;i<k;i++){
        if(i==m)continue;
        int fx=f(edge[i].from);
        int fy=f(edge[i].to);
        if(fx!=fy){
            pre[fx]=fy;
            sum+=edge[i].cost;
            flag++;
        }
        if(flag==n-1)break;
    }
    if(flag!=n-1)return 0;
    return sum==ans;
}

int main(){
    int t,m,a,b,c;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        memset(edge,0,sizeof(edge));
        k=0;
        while(m--){
            scanf("%d%d%d",&a,&b,&c);
            addEdge(a,b,c);
        }
        sort(edge,edge+k,cmp);
        int flag=0;
        for(int i=1;i<=n;i++)pre[i]=i;
        int ans=0;
        for(int i=0;i<k;i++){//求解出最小生成树
            int fx=f(edge[i].from);
            int fy=f(edge[i].to);
            if(fx!=fy){
                pre[fx]=fy;
                ans+=edge[i].cost;
                flag++;
                edge[i].flag=1;
            }
            if(flag==n-1)break;
        }
        int uni=0;
        for(int i=0;i<k;i++){//i代表的是边号,从MST的每一条边开始,不要这条边,再进行一次循环找MST,若值相同则有重复
            if(edge[i].flag==0)continue;
            for(int j=1;j<=n;j++)pre[j]=j;
            uni=kruskal(i,ans);//去掉序号为i的边,找MST
            if(uni==1)break;//不是独一无二的MST
        }
        if(uni==1)printf("Not Unique!\n");
        else printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37579232/article/details/80272561