UVA 10600 & 次小生成树

这道题涉及次小生成树,有必要先弄明白次小生成树是怎么一回事。

次小生成树,顾名知义。一个定理是,次小生成树可以由最小生成树交换一条边得到。这怎么证明,可以上网搜一下。但有必要提醒的是,交换过来的这样一条边,必须是未成使用过的(即不是最小生成树的边)。而且,交换走的边,必须是已存在的,而且是两点间最短路径的最大边权的边。

所以,可以在求最小生成树时求这最大边权的边。

 1 void prim(){
 2     memset(f,0,sizeof(f));
 3     least[1]=0;
 4     for(int i=2;i<=n;i++){
 5         least[i]=map[1][i];
 6         if(least[i]!=inf)
 7         pre[i]=1;
 8     }
 9     vis[1]=true;
10     for(int i=1;i<=n;i++){
11         int min=inf,p=-1;
12         for(int k=1;k<=n;k++){
13             if(least[k]<min&&!vis[k]){
14                 p=k; min=least[k];
15             }
16         }
17
18         if(p==-1) return ;
19         ans1+=min;
20         used[pre[p]][p]=used[p][pre[p]]=1;
21         for(int j=1;j<=n;j++){ //应该是已访问的点,这样边是已使用
22         if(vis[j])
23         f[j][p]=max(f[j][pre[p]],map[pre[p]][p]);
24         f[p][j]=f[j][p];
25         }
26         vis[p]=true;
27         for(int k=1;k<=n;k++){
28             if(!vis[k]&&map[p][k]<least[k]){
29                 least[k]=map[p][k];
30                 pre[k]=p;
31             }
32         }
33     }
34 }

UV10600是裸的次小生成树题。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5
 6 using namespace std;
 7 const int MAXN=105;
 8 const int inf=10000000;
 9 int map[MAXN][MAXN]; int f[MAXN][MAXN];
10 bool exist[MAXN][MAXN],used[MAXN][MAXN];
11 int least[MAXN],pre[MAXN]; bool vis[MAXN];
12 int n,m,ans1,ans2;
13
14 void prim(){
15 memset(f,0,sizeof(f));
16 least[1]=0;
17 for(int i=2;i<=n;i++){
18 least[i]=map[1][i];
19 if(least[i]!=inf)
20 pre[i]=1;
21 }
22 vis[1]=true;
23 for(int i=1;i<=n;i++){
24 int min=inf,p=-1;
25 for(int k=1;k<=n;k++){
26 if(least[k]<min&&!vis[k]){
27 p=k; min=least[k];
28 }
29 }
30
31 if(p==-1) return ;
32 ans1+=min;
33 used[pre[p]][p]=used[p][pre[p]]=1;
34 for(int j=1;j<=n;j++){
35 if(vis[j])
36 f[j][p]=max(f[j][pre[p]],map[pre[p]][p]);
37 f[p][j]=f[j][p];
38 }
39 vis[p]=true;
40 for(int k=1;k<=n;k++){
41 if(!vis[k]&&map[p][k]<least[k]){
42 least[k]=map[p][k];
43 pre[k]=p;
44 }
45 }
46 }
47 }
48
49 void secondT(){
50 ans2=inf;
51 for(int i=1;i<=n;i++){
52 for(int j=1;j<=n;j++){
53 if(exist[i][j]&&!used[i][j]&&ans1 + map[i][j] - f[i][j] < ans2)
54 ans2=ans1 + map[i][j] - f[i][j];
55 }
56 }
57 }
58
59 int main(){
60 int T;
61 scanf("%d",&T);
62 while(T--){
63 scanf("%d%d",&n,&m);
64 int u,v,d;
65 ans1=ans2=0;
66 memset(exist,-1,sizeof(exist));
67 for(int i=1;i<=n;i++){
68 for(int j=i;j<=n;j++)
69 map[i][j]=map[j][i]=inf;
70 }
71 for(int i=1;i<=m;i++){
72 scanf("%d%d%d",&u,&v,&d);
73 map[u][v]=map[v][u]=d;
74 exist[u][v]=exist[v][u]=1;
75 }
76 memset(pre,-1,sizeof(pre));
77 memset(used,0,sizeof(used));
78 memset(vis,false,sizeof(vis));
79 prim();
80 secondT();
81 printf("%d %d\n",ans1,ans2);
82 }
83 return 0;
84 }

UVA 10600 & 次小生成树

时间: 2024-10-29 15:33:19

UVA 10600 & 次小生成树的相关文章

UVA - 1494 Qin Shi Huang&#39;s National Road System (类次小生成树)

Description During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China -- they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of the kingdom Qin. Through 9 years of wars, he finally con

UVA - 10462 Is There A Second Way Left?(次小生成树)

题目大意:给出一张图,看能形成几个生成树 解题思路:先判断能否形成生成树,在判断是否有次小生成树 #include <cstdio> #include <cstring> #include <vector> using namespace std; #define N 110 #define M 410 #define INF 0x3f3f3f3f struct Edge{ int from, to, cost, next; }E[M]; int head[N], d[

UVA 10462 Is There A Second Way Left? (次小生成树+kruskal)

题目大意: Nasa应邻居们的要求,决定用一个网络把大家链接在一起.给出v个点,e条可行路线,每条路线分别是x连接到y需要花费w. 1:如果不存在最小生成树,输出“No way”. 2:如果不存在次小生成树,输出“No second way”. 3:如果两者都存在,输出次小生成树的长度. 解题思路: 次小生成数+kruskal模板 1 #include <cmath> 2 #include <queue> 3 #include <string> 4 #include &

[kuangbin带你飞]专题八 生成树 - 次小生成树部分

百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么尝试加入它 然后为了不成环 要在环中去除一条边 为了达到"次小"的效果 减去最长的 即F[i][k] 求一下此时的数值 不断更新次小值 2 kru 记录下被加入到最小生成树中的线段 然后进行n-1次枚举 每次都跳过一条被记录的边 求一次kru 得到的值为-1或者一个可能成为次小的值 不断更

kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一个环,如果还要维护处树的特点 那么就要在这个环上删去一条边,这样他还是树,删掉的边显然是这条链上权值最大边更可能形成次小生成树.那么就有2中方法可以做. 第一种PRIM在prim时候直接可以做出这个从I到J的链上权值最大的值MAX[i][j]; 同时可以用kruskal同样方式标记树边,然后DFS跑

最小瓶颈路与次小生成树

简介: 最小生成树是图论里面一类经典问题,可以有很多种变形,其中最小瓶颈路和次小生成树就是两种比较经典的变形.最小瓶颈路就是在两个结点之间求一条最长边最短的路径,而次小生成树则是所有生成树中权值排名第二的生成树(可以和最小生成树相等).下面我们分别来看看这两个问题. 最小瓶颈路: 给定一个加权无向图,并给定无向图中两个结点u和v,求u到v的一条路径,使得路径上边的最大权值最小.这个问题可以稍微加强一下,即求很多对结点之间的最小瓶颈路. 无向图中,任意两个结点的最小瓶颈路肯定在最小生成树上.因此,

HDU4081 Qin Shi Huang&#39;s National Road System【Kruska】【次小生成树】

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3979    Accepted Submission(s): 1372 Problem Description During the Warring States Period of ancient China(4

Ural 1416 Confidential,次小生成树

不严格次小生成树. 注意图可能不连通. #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn = 505; const int INF = 1e7; bool vis[maxn]; int d[maxn]; int pre[maxn]; int Max[maxn][maxn]; int g[

TOJ--1278--最小生成树

今天中午做的 第一次用邻接表去实现... 我就写了下prim的 相比于kruskal 还是更喜欢它多一点... 虽然知道prim+heap优化 可是我写不来..... 对于 heap 虽然觉得它的概念很简单 但实现起来真的好伤啊.. 我想 对于prim的理解应该差不多了 基本上可以直接手码出来了 虽然这个很简单.... 以前原来就有一篇 prim的介绍 那我就懒的写了 直接上代码吧  一般都是用  邻接矩阵实现的.. #include <iostream> #include <cstri