次小生成树(POJ1679/CDOJ1959)

POJ1679

首先求出最小生成树,记录权值之和为MinST。然后枚举添加边(u,v),加上后必形成一个环,找到环上非(u,v)边的权值最大的边,把它删除,计算当前生成树的权值之和,取所有枚举加边后生成树权值之和的最小值

思路:

最小生成树唯一性判断,求次小生成树的val再与最小生成树比较。
1.先用prim算法求出最小生成树。并在其过程中保存加入到MST中的Max[i][j]( i 到 j 路径中的最大边 ) 
2.对未加入MST的边进行遍历:从MST中去掉i j路径中的最大边,加入未访问边G[i][j],如果得到的生成树的权值和MST的相等,则存在次小生成树的权值=MST的权值和

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cmath>
 5 #include <cstring>
 6 using namespace std;
 7 #define INF 0x3f3f3f3f
 8
 9 const int N = 1e3+6;
10 int G[N][N]; // graph matrix
11 int f[N];    // pre node
12 int vis[N];  // visited node
13 int dis[N];  // main matrix: the edges(set-u)
14 int mark[N][N];
15 int Max[N][N]; // path from i to j max edge
16 int n,m,best;
17
18 int prim(int v)
19 {
20     int ans=0;
21     vis[v]=1;
22     for(int i=1;i<=n;i++)
23     {
24         dis[i]=G[v][i];
25         f[i]=v;
26     }
27     dis[v]=0;
28     for(int i=1;i<n;i++) // n-1
29     {
30         int u=-1;
31         for(int j=1;j<=n;j++)
32             if(!vis[j]&&(u==-1||dis[j]<dis[u]))u=j;
33         if(u==-1)break;
34         vis[u]=1;
35         mark[u][f[u]] = mark[f[u]][u] = 1;
36         ans += dis[u];
37         for(int j=1;j<=n;j++)
38         {
39             // compare with visited node record path max edge
40             if(vis[j])Max[u][j]=Max[j][u]=max(Max[j][f[u]],dis[u]);
41             if(!vis[j]&&dis[j]>G[u][j])
42             {
43                 dis[j]=G[u][j];
44                 f[j]=u;
45             }
46         }
47     }
48     return ans;
49 }
50
51 int SMST()
52 {
53     int mini=INF;
54     for(int i=1;i<=n;i++)
55         for(int j=1;j<=n;j++)  //or for(int j=i+1;j<=n;j++)
56         {
57             if(i!=j&&!mark[i][j])
58                 mini = min(mini,best+G[i][j]-Max[i][j]);
59         }
60     return mini;
61 }
62
63 int main()
64 {
65     int x,y,w,T;
66     scanf("%d",&T);
67     while(T--)
68     {
69         memset( vis, 0 ,sizeof(vis) );
70         memset( Max, 0 ,sizeof(Max) );
71         memset( f, 0 ,sizeof(f) );
72         memset( dis, 0 ,sizeof(dis) );
73         memset( mark, 0 ,sizeof(mark) );
74         scanf("%d%d",&n,&m);
75         for(int i=1;i<=n;i++)
76             for(int j=1;j<=n;j++)
77             {
78                 if(i==j)G[i][j]==0;
79                 else G[i][j]=INF;
80             }
81         for(int i=0;i<m;i++)
82         {
83             scanf("%d%d%d",&x,&y,&w);
84             G[x][y]=w;
85             G[y][x]=w;
86         }
87         best = prim(1);
88         int temp = SMST();
89         if(temp == best)
90             printf("Not Unique!\n");
91         else
92             printf("%d\n",best);
93     }
94     return 0;
95 }

CDOJ 1959

思路:这道题会出现重边,用Kruskal算法处理起来比较方便。(用邻接表方便,邻接矩阵还要考虑同两点之间的多条权值相同的边。)

次小生成树的权值如果等于最小生成树的权值, 其替换边只会是权值相同的边,于是可以把权值相同边放在一起考虑,分别判断全部没有合并时有多少可以合并(cnt1记录的是可以加入集合的边数),边合并边判断有多少可以合并(cnt2记录的是选中一条加入到集合),如果可选的大于构成最小生成树所需要的,那么就存在一种相同的边权可以替换原来的,从而最小生成树不唯一。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 const int N = 2e5+6;
 5 struct Node
 6 {
 7     int u,v;
 8     LL w;
 9 }G[N];
10
11 int n,m;
12 int f[2002];
13 int find(int x)
14 {
15     return x==f[x]?x:f[x]=find(f[x]);
16 }
17
18 bool cmp(Node & a, Node & b)
19 {
20     return a.w<b.w;
21 }
22
23 void kruskal()
24 {
25     int cnt1=0;
26     int cnt2=0;
27     for(int i=1;i<=n;i++)f[i]=i;
28     sort(G,G+m,cmp);
29     for(int i=0;i<m;)
30     {
31         int j=i;
32         while(j<m&&G[j].w==G[i].w)
33         {
34             int u = find(G[j].u);
35             int v = find(G[j].v);
36             if(u!=v)cnt1++;
37             j++;
38         }
39         j=i;
40         while(j<m&&G[j].w==G[i].w)
41         {
42             int u = find(G[j].u);
43             int v = find(G[j].v);
44             if(u!=v){
45                 cnt2++;
46                 f[u]=v;
47             }
48             j++;
49         }
50         i=j;
51         if(cnt1>cnt2)break;
52     }
53     if( cnt1 > cnt2 ){
54         printf("zin\n");
55     }else{
56         printf("ogisosetsuna\n");
57     }
58 }
59
60 int main()
61 {
62     int x,y;
63     LL w;
64     cin>>n>>m;
65     for(int i=0;i<m;i++)
66     {
67         cin>>x>>y>>w;
68         G[i].u=x;
69         G[i].v=y;
70         G[i].w=w;
71     }
72     kruskal();
73     return 0;
74 }

原文地址:https://www.cnblogs.com/demian/p/9188918.html

时间: 2024-08-04 15:58:32

次小生成树(POJ1679/CDOJ1959)的相关文章

POJ1679 The Unique MST 【次小生成树】

The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20421   Accepted: 7183 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undire

poj1679+次小生成树

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 followin

[POJ1679]The Unique MST 次小生成树

题目链接:http://poj.org/problem?id=1679 给你一个图的连通情况,询问你此图的最小生成树是否唯一. 假如最小生成树唯一,即生成树连通所有节点的权值和唯一.假如不唯一,那么存在另一条最小生成树使得权值等于之前最小生成树的权值. 换个思路考虑,也就是次小生成树的权值与最小生成树的权值相同,那么问题就变成了求次小生成树的权值. 我选择的是先求出最小生成树,将树上用到的边都保存下来.接着分别将每一条用到的边摘下来,再求一次最小生成树.假如不包含当前删掉的边生成的生成树的所选边

POJ1679 The Unique MST【Kruskal】【次小生成树】

The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 21304 Accepted: 7537 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undirected

poj1679次小生成树入门题

次小生成树求法:例如求最小生成树用到了 1.2.4这三条边,总共5条边,那循环3次的时候,每次分别不用1.2.4求得最小生成树的MST,最小的MST即为次小生成树 如下代码maxx即每次删去1,2,4边之后求得的最大边 #include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstd

POJ1679(次小生成树)

The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24201   Accepted: 8596 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undire

poj1679——The Unique MST(次小生成树,Kruskal)

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 followin

次小生成树

次小生成树:所谓的次小生成树,是指在边集与某一最小生成树的边集不完全相同的其它生成树中值最小的那个.因此在数值上,最小生成树可能会等于次小生成树,这种情况也可以看做最小生成数. 思路:最直观的解法是,首先求出最小生成树,并且记录最小生成树中的边,然后再枚举删除最小生成树的边并同时求最小生成树. 以POJ1679为例,Kruskal求次小生成树代码如下: 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm>

次小生成树的模版

求次小生成树的步骤是: 1.求出最小生成树MST,用一个矩阵maxe[u][v]记录在MST中连接u-v的路径中权值最大的边. 2.枚举所有不在T中的边u-v,加入边u-v,删除权值为max[u][v]的边,不断枚举找到次小生成树. 由于邻接矩阵建图无法储存平行边(重边),我们在建图的时候都是取当前最小值.所以用prim做的话,很可能出错.但是prim也是有市场的,当没有平行边,并且定点数比较少的时候,用prim就有优势.如果有平行边,就必须用kruskal.用链式前向星建图. 下面是两个模版,