• POJ 1679 判最小生成树的不唯一性 或 利用次小生成树求解


    题目大意:

    给定一个无向图,寻找它的最小生成树,如果仅有一种最小生成树,输出所有边的和,否则输出unique!

    根据kruscal原理来说,每次不断取尽可能小的边不断添加入最小生成树中,那么可知如果所有边的长度都不相同,那么kruscal取得过程必然只有一种情况,由小到大

    所以要是存在多种情况的最小生成树,那么必然是存在相同的边

    初始将所有相同的边进行标记,生成第一次最小生成树后,不断去除其中带标记的边,然后再计算最小生成树,判断能否得到同样的答案,如果可以,说明不止一种情况

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 #define N 105
     6 int fa[N] , same[N] , first[N] , k;
     7 int rec[N] , amo;//rec[]记录MST中含有相同长度边的位置,amo记录其数量
     8 struct Edge{
     9     int x,y,d,next,flag;
    10     bool same;
    11     bool operator<(const Edge &m) const{
    12         return d<m.d;
    13     }
    14 }e[N*N];
    15 
    16 int find_head(int x)
    17 {
    18     while(fa[x]!=x) x=fa[x];
    19     return x;
    20 }
    21 
    22 bool Union(int x,int y)
    23 {
    24     int fa_x = find_head(x);
    25     int fa_y = find_head(y);
    26     fa[fa_x] = fa_y;
    27     return fa_x == fa_y;
    28 }
    29 
    30 void add_edge(int x, int y , int d)
    31 {
    32     e[k].x=x , e[k].y=y , e[k].d=d , e[k].flag=1 , e[k].next=first[x];
    33     e[k].same = false;
    34     first[x] = k++;
    35 }
    36 
    37 int cal_MST(int n , int flag)
    38 {
    39     int ans = 0 , cnt=0;
    40     for(int i=1 ; i<=n ; i++) fa[i]=i;
    41     for(int i=0 ; i<k ; i++){
    42         if(e[i].flag==1){
    43             if(!Union(e[i].x , e[i].y)){
    44                 ans+=e[i].d;
    45                 if(e[i].same && flag){
    46                     rec[amo++] = i;
    47                 }
    48                 cnt++;
    49                 if(cnt == n-1) break;
    50             }
    51         }
    52     }
    53     return ans;
    54 }
    55 
    56 int main()
    57 {
    58     int T;
    59     scanf("%d" , &T);
    60     while(T--)
    61     {
    62         int n , m , x , y , d;
    63         scanf("%d%d" , &n , &m);
    64         k=0;
    65         memset(first , -1 , sizeof(first));
    66         for(int i=0 ; i<m ; i++){
    67             scanf("%d%d%d" , &x , &y , &d);
    68             add_edge(x , y , d);
    69         }
    70 
    71         sort(e , e+k);
    72         //对存在相同边的边进行标记
    73         for(int i=1 ; i<k ; i++)
    74             if(e[i].d == e[i-1].d) e[i].same=e[i-1].same=true;
    75         amo = 0;
    76         int ans = cal_MST(n , 1);
    77         bool is_unique = true;
    78         for(int i=0 ; i<amo ; i++){
    79             e[rec[i]].flag = 0;
    80             int t=cal_MST(n , 0);
    81             if(t == ans){
    82                 is_unique=false;
    83                 break;
    84             }
    85             e[rec[i]].flag = 1;
    86         }
    87         if(is_unique) printf("%d
    " , ans);
    88         else puts("Not Unique!");
    89     }
    90     return 0;
    91 }
    View Code

    上面那个明显复杂度比较高

    我们可以求解出次小生成树的值与最小生成树的值进行比较判断是否唯一

    先求出最小生成树,用二维数组mx[][]记录最小生成树上两个点之间路径上最长边的长度

    然后找到每一条不属于最小生成树的边u,v ,这样可以与原最小生成树中u->v的路径形成一个环,那么最后需要在环中删去一条最长边,那么只要不断得到这个差值的最小值

    用最小生成树的值减去他就可以了

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 #define N 105
     6 const int INF = 0x3f3f3f3f;
     7 int mx[N][N] , w[N][N];
     8 int n , m;
     9 int d[N] , connect[N];
    10 bool vis[N][N] , in[N];
    11 
    12 int prim()
    13 {
    14     int ret = 0;
    15     memset(vis , 0 , sizeof(vis));
    16     memset(connect , 0 , sizeof(connect));
    17     memset(in , 0 , sizeof(in));
    18     memset(mx , 0 , sizeof(mx));
    19     d[1] = INF , in[1] = true;
    20     for(int i=2 ; i<=n ; i++)
    21         if(w[1][i]>=0){
    22             d[i] = w[1][i];
    23             connect[i] = 1;
    24         }
    25         else d[i] = INF;
    26 
    27     for(int i=1 ; i<n ; i++){
    28         int minn = INF , index = 0;
    29         for(int j=1 ; j<=n ; j++){
    30             if(in[j]) continue;
    31             if(d[j]<minn) minn=d[j] , index=j;
    32         }
    33         int u = connect[index];
    34         d[index] = INF , vis[index][u] = vis[u][index] = true;
    35         mx[index][u] = mx[u][index] = minn , in[index] = true , ret+=minn;
    36         for(int j=1 ; j<=n ; j++){
    37             if(in[j] || w[index][j]<0) continue;
    38             if(w[index][j]<d[j]) d[j] = w[index][j] , connect[j] = index;
    39         }
    40         for(int j=1 ; j<=n ; j++){
    41             if(!in[j]) continue;
    42             mx[j][index] = mx[index][j] = max(mx[index][j] , max(mx[index][u] , minn));
    43         }
    44     }
    45     return ret;
    46 }
    47 
    48 int sec_mst(int mst)
    49 {
    50     int del = INF;
    51     for(int i=1 ; i<=n ; i++){
    52         for(int j=i+1 ; j<=n ; j++){
    53             if(!vis[i][j] && w[i][j]>=0){
    54                 del = min(del , mx[i][j]-w[i][j]);
    55             }
    56         }
    57     }
    58     return mst-del;
    59 }
    60 
    61 int main()
    62 {
    63   //  freopen("in.txt" , "r" , stdin);
    64     int T;
    65     scanf("%d" , &T);
    66     while(T--)
    67     {
    68         scanf("%d%d" , &n , &m);
    69         memset(w , -1 , sizeof(w));
    70         int u , v , wei;
    71         while(m--){
    72             scanf("%d%d%d" , &u , &v , &wei);
    73             w[u][v] = w[v][u] = wei;
    74         }
    75         int ret = prim();
    76         int sec = sec_mst(ret);
    77         if(ret == sec) puts("Not Unique!");
    78         else printf("%d
    " , ret);
    79     }
    80     return 0;
    81 }
  • 相关阅读:
    NetCore+Dapper WebApi架构搭建(三):添加实体和仓储
    NetCore+Dapper WebApi架构搭建(二):底层封装
    NetCore+Dapper WebApi架构搭建(一):基本框架
    net core WebApi——缓存神器Redis
    net core Webapi基础工程搭建(六)——数据库操作_Part 2
    net core Webapi基础工程搭建(七)——小试AOP及常规测试_Part 2
    springBoot+mybatisPlus小demo
    JAVA并发(一)
    tomcat解析
    JAVA并发-线程状态
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4361988.html
Copyright © 2020-2023  润新知