• 【POJ1679】The Unique MST


      1 //ver1: Kruskal+暴力枚举删除边
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<algorithm>
      5 using namespace std;
      6 int t,n,m,first;
      7 int a,ok,minx,p[101];
      8 struct edge{
      9     int v1,v2,d,v;  //v标记MST中的每一条边 
     10 }e[10001];
     11 int findp(int x){
     12     return x==p[x]?x:p[x]=findp(p[x]);
     13 }
     14 int cmp(edge a,edge b){
     15     return a.d<b.d;
     16 }
     17 void init(){
     18     cin>>n>>m;
     19     ok=1;first=1;
     20     for(int i=0;i<m;i++){
     21         cin>>e[i].v1>>e[i].v2>>e[i].d;
     22         e[i].v=0;
     23     }
     24     sort(e,e+m,cmp);
     25 }
     26 int Kruskal(){
     27     for(int i=1;i<=n;i++) 
     28         p[i]=i;
     29     a=n; int sum=0;
     30     for(int i=0;i<m;i++){
     31         int p1=findp(e[i].v1),p2=findp(e[i].v2);
     32         if(p1!=p2){
     33             sum+=e[i].d;
     34             a--;
     35             p[p1]=p2;
     36             if(first) e[i].v=1;  //边i属于MST 
     37         }
     38         if(a==1) break;
     39     }
     40     if(a==1) return sum;
     41     return -1;
     42 }
     43 int main(){
     44     cin>>t;
     45     while(t--){
     46         init();
     47         minx=Kruskal();        //求MST 
     48         first=0;               //注意MST已经求过了 
     49         for(int i=0;i<m;i++){
     50             if(e[i].v){        //删除MST中的一条边,再添加一条边形成连通图 
     51                 int t=e[i].v1; //把这条件的两个点变成一个点,从而在下面的Kruskal中不会再选择这条边 
     52                 e[i].v1=e[i].v2;
     53                 int sum=Kruskal();
     54                 if(sum==minx) {ok=0;break;}
     55                 e[i].v1=t;
     56             } 
     57         }
     58         if(ok) cout<<minx<<endl;
     59         else cout<<"Not Unique!
    ";
     60     }
     61 }
     62 //ver2:Kruskal+判断是否存在权值相等且连接的等价集合相同
     63 #include<cstdio>
     64 #include<iostream>
     65 #include<algorithm>
     66 using namespace std;
     67 int t,n,m,a,minx,ok,p[101];
     68 struct edge{
     69     int x,y,w;
     70 }e[10001];
     71 int cmp(edge a,edge b){
     72     return a.w<b.w;
     73 }
     74 int findp(int x){
     75     return x==p[x]?x:p[x]=findp(p[x]);
     76 }
     77 void init(){
     78     minx=0;ok=1;
     79     scanf("%d%d",&n,&m); a=n;
     80     for(int i=1;i<=n;i++) p[i]=i;
     81     for(int i=0;i<m;i++)
     82         scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
     83     sort(e,e+m,cmp);
     84 }
     85 void Kruskal(){
     86     for(int i=0;i<m;i++){
     87         int p1=findp(e[i].x),p2=findp(e[i].y);
     88         if(p1!=p2){
     89             for(int j=i+1;j<m;j++)
     90                 if(e[i].w==e[j].w){
     91                     //判断链接的是否是相同的集合
     92                     int p3=findp(e[j].x),p4=findp(e[j].y);
     93                     if(p3==p1&&p4==p2||p3==p2&&p4==p1){
     94                         ok=0;
     95                         return;
     96                     } 
     97                 }
     98                 else break;//由于e[]是有序的,发现权值不同,立即退出循环
     99             p[p1]=p2;
    100             minx+=e[i].w;
    101             a--;
    102         }
    103         if(a==1) break;
    104     }
    105 }
    106 int main()
    107 {
    108     scanf("%d",&t);
    109     while(t--){
    110         init();
    111         Kruskal();
    112         if(ok) printf("%d
    ",minx);
    113         else printf("Not Unique!
    ");
    114     }
    115 }
    116 //ver3: 可以前后求两次MST,在权值相同的情况下,第一次边编号小的优先选,第二次边编号大的优先选,
    117 //判断两次MST是否相同即可(一是最短路径和是否相等,二是所有的边是否相同) 

    判断最小生成树是否唯一

  • 相关阅读:
    【流水账】2021-06-19 Day-09
    【流水账】2021-06-18 Day-08
    【流水账】2021-06-16 Day-06
    【流水账】2021-06-15 Day-05
    .Net调用Java的实现方法
    优先队列的实例题
    栈的相关程序题
    重载函数
    卡特兰数
    关于全排列的递归
  • 原文地址:https://www.cnblogs.com/sulley/p/7868536.html
Copyright © 2020-2023  润新知