POJ 1679 The Unique MST

题意就是求一个MST,然后求一个次小生成树(可能与MST相等),然后问我们这个次小生成树是否与MST的总权重相等。

朴素的想法是求出一个MST后把它上面的每个边删一次(一次就够,因为次小生成树如果存在必然与MST有n-1条公共边),删后再求一次MST,然而求 n-1 次 MST明显不实际。

我们转换一下思路,不是删掉边加边而是替换边,假设加的边是 G[i][j] (没用过的)那么被替换的边一定是MST上 i -> j 的路径中最大的边(否则得到一定不是次小生成树),如此只要在求一次MST的基础上多加O(n^2)。

为了达到这个目的我们需要用prim在求MST的同时处理处path[i][j]。具体参见代码。

if(vis[j]&&u!=j)//path[u][j] means the longest edges of the path from u to j
                path[j][u]=path[u][j]=max(path[j][pre[u]],dist[u]);

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <vector>
  5 #include <utility>
  6 
  7 using namespace std;
  8 #define fst first
  9 #define scd second
 10 #define pb(x) push_back((x))
 11 #define mkp(x,y) make_pair((x),(y)) 
 12 #define ist(x) insert((x))
 13 typedef long long ll;
 14 typedef pair<int ,int > pii;
 15 typedef pair<ll ,ll > pll;
 16 typedef vector< int > vi;
 17 ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
 18 ll qPow(ll a,ll b,ll mod){ ll ret=1ll;while(b){ if(b&1) ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret; }
 19 
 20 const int INF=0x3f3f3f3f;
 21 int n,m;// number of V and E
 22 int G[128][128];
 23 bool vis[128],used[128][128];
 24 int path[128][128],dist[128];
 25 int pre[128];
 26 
 27 int prim(int v){// v is start
 28     memset(vis,false,sizeof(vis));
 29     memset(used,false,sizeof(used));//
 30     memset(path,0,sizeof(path));//
 31     for(int i=1;i<=n;++i){
 32         dist[i]=G[v][i];
 33         pre[i]=v;
 34     }
 35     vis[v]=true;
 36     
 37     int sum=0;
 38     int u,tmp;// u is index of tmp dot
 39     for(int i=1;i<n;++i){// n-1 edges
 40         u=v;
 41         tmp=INF;
 42         for(int j=1;j<=n;++j){// find the nearest vertex
 43             if(!vis[j]&&dist[j]<tmp){
 44                 tmp=dist[j];
 45                 u=j;
 46             }
 47         }
 48         vis[u]=true;
 49         sum+=dist[u];
 50         used[u][pre[u]]=used[pre[u]][u]=true;
 51 
 52         for(int j=1;j<=n;++j){
 53             if(vis[j]&&u!=j)//path[u][j] means the longest edges of the path from u to j
 54                 path[j][u]=path[u][j]=max(path[j][pre[u]],dist[u]);
 55             if(!vis[j]&&dist[j]>G[u][j]){//relax
 56                 dist[j]=G[u][j];
 57                 pre[j]=u;// 
 58             }
 59         }
 60     }
 61     return sum;
 62 }
 63 
 64 int second_MST(int tot) {
 65     int ans=INF;
 66     //puts("test in second_MST:
");
 67     for(int i=1;i<=n;++i){
 68         for(int j=1;j<=n;++j){
 69             //printf("%d %d : used=%d , path=%d ,G=%d
",i,j,used[i][j]?1:0,path[i][j],G[i][j]);
 70             if(!used[i][j]&&i!=j)
 71             ans=min(ans,tot-path[i][j]+G[i][j]);
 72         }
 73     }
 74     return ans;
 75 }
 76 
 77 int main(){
 78     int Test;
 79     scanf("%d",&Test);
 80     while(Test--) {
 81         scanf("%d%d",&n,&m);
 82         
 83         // initial
 84         for(int i=1;i<=n;++i)
 85             for(int j=1;j<=n;++j) G[i][j]=INF;
 86         
 87         for(int i=0;i<m;++i){
 88             int u,v,w;
 89             scanf("%d%d%d",&u,&v,&w);
 90             G[u][v]=w,G[v][u]=w;
 91         }
 92         
 93         int tot = prim(1);
 94         int ans=second_MST(tot);
 95         //printf("tot and ans : %d , %d
",tot,ans);
 96         if(ans==tot) puts("Not Unique!");
 97         else printf("%d
",tot);
 98     } 
 99     return 0;
100 }
View Code
原文地址:https://www.cnblogs.com/Kiritsugu/p/9635187.html