zoukankan      html  css  js  c++  java
  • POJ_1679_The Unique MST(次小生成树)

    Description

    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!

    题意:问最小生成树是否唯一。

    分析:求次小生成树,推断次小生成树和最小生成树是否相等。

    求次小生成树的步骤:

    (1)先用Prime求出最小生成树MST,在Prime的同一时候用一个矩阵mmax[ ][ ]记录在MST中连接随意两点u,v的唯一路径中权

    值最大的那条边的权值。做法:Prime是每次添加一个节点t。用该点新加入MST的边与它前一个加入MST的点的mmax的值做比较。

    (2)枚举最小生成树以外的边,并删除该边所在环上权值最大的边。

    (3)取得的全部生成树中权值最小的一棵即为所求。

    算法的时间复杂度为O(n^2)。

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 using namespace std;
      5 #define maxn 111
      6 #define inf 0x3f3f3f3f
      7 
      8 int map[maxn][maxn],mmax[maxn][maxn];//map邻接矩阵存图,mmax示最小生成树中i到j的最大边权 
      9 bool used[maxn][maxn];//判断该边是否加入最小生成树
     10 int pre[maxn],dis[maxn];//pre用于mmax的构建,装前一个放入MST的结点,dis用于构建MST 
     11 
     12 void init(int n)
     13 {
     14     for (int i=1;i<=n;i++)//图初始化 
     15     {
     16         for (int j=1;j<=n;j++)
     17         {
     18             if (i==j)
     19             {
     20                 map[i][j]=0;
     21             }
     22             else
     23             {
     24                 map[i][j]=inf;
     25             }
     26         }
     27     }
     28 }
     29 
     30 void read(int m)
     31 {
     32     int u,v,w;
     33     for (int i=0;i<m;i++)//读入图 
     34     {
     35         scanf("%d%d%d",&u,&v,&w);
     36         map[u][v]=map[v][u]=w;
     37     }
     38 }
     39 int prime(int n)//构建MST 
     40 {
     41     int ans=0;
     42     bool vis[maxn];
     43     memset(vis,false,sizeof(vis));
     44     memset(used,false,sizeof(used));
     45     memset(mmax,0,sizeof(mmax));
     46     for (int i=2;i<=n;i++)
     47     {
     48         dis[i]=map[1][i];
     49         pre[i]=1;//1点为第一个放入MST的点,先设为所有点的前驱结点 
     50     }
     51     pre[1]=0;
     52     dis[1]=0;
     53     vis[1]=true;
     54     for (int i=2;i<=n;i++)
     55     {
     56         int min_dis=inf,k;
     57         for (int j=1;j<=n;j++)
     58         {
     59             if (vis[j]==0&&min_dis>dis[j]) 
     60             {
     61                 min_dis=dis[j];
     62                 k=j;
     63             }
     64         }
     65         if (min_dis==inf)//如果不存在最小生成树
     66         {
     67             return -1;
     68         }
     69         ans+=min_dis;
     70         vis[k]=true;
     71         used[k][pre[k]]=used[pre[k]][k]=true;//标记为放入MST的点 
     72         for (int j=1;j<=n;j++)
     73         {
     74             if (vis[j])
     75             {
     76                 mmax[j][k]=mmax[k][j]=max(mmax[j][pre[k]],dis[k]);//最小生成树环的最大边
     77             }
     78             if (!vis[j]&&dis[j]>map[k][j])
     79                 {
     80                     dis[j]=map[k][j];
     81                     pre[j]=k;
     82                 }
     83         }
     84     }
     85     return ans;//最小生成树的权值之和
     86 }
     87 int smst(int n,int min_ans)//min_ans 是最小生成树的权值和
     88 {
     89     int ans=inf;
     90     for (int i=1;i<=n;i++)//枚举最小生成树之外的边 
     91     {
     92         for (int j=i+1;j<=n;j++)
     93         {
     94             if (map[i][j]!=inf&&!used[i][j])
     95             {
     96                 ans=min(ans,min_ans+map[i][j]-mmax[i][j]);//该边次小MST的权值为MST加上该边再减去该边所在环的最大MST边 
     97             }
     98         }
     99     }
    100     if (ans==inf)
    101     {
    102         return -1;
    103     }
    104     return ans;
    105 }
    106 void solve(int n)
    107 {
    108     int ans=prime(n);
    109     if (ans==-1)
    110     {
    111         puts("Not Unique!");
    112         return;
    113     }
    114     if (smst(n,ans)==ans)//次小MST权值等于MST说明MST不唯一 
    115     {
    116         printf("Not Unique!
    ");
    117     }
    118     else 
    119     {
    120         printf("%d
    ",ans);
    121     }
    122 }
    123 int main()
    124 {
    125     int t,n,m;
    126     
    127     scanf("%d",&t);
    128     while (t--)
    129     {
    130         scanf("%d%d",&n,&m);
    131         init(n);
    132         read(m);
    133         solve(n);
    134     }
    135     
    136     return 0;
    137 }
  • 相关阅读:
    c# yield关键字原理详解
    Linux环境基于CentOS7 搭建部署Docker容器
    关于c#中委托使用小结
    推荐一本好的c#高级程序设计教程
    WEB网站常见受攻击方式及解决办法
    判断URL是否存在
    提升高并发量服务器性能解决思路
    分享asp.net学习交流社区
    js中对arry数组的各种操作小结
    jQuery动态实现title的修改 失效问题
  • 原文地址:https://www.cnblogs.com/hemeiwolong/p/9015974.html
Copyright © 2011-2022 走看看