生成树专题

uvalive3887

给定一个带权的无向图,求得一棵最小生成树,是的树中的最大边权-最小边权的差值最小

分析:当确定一个最小边时(其他的边的权值都比他大),那么之后按照kruskal算法得到的最小生成树,

此时得到的最小生成树的最大权值也肯定是最小的,因为是kruskal是按照贪心来选边的。

所以只要不断的枚举是哪条边作为最小边,然后生成最小生成树,记录所有差值中最小的一个就是答案。

时间复杂度是O(m*m*logm)

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 #pragma warning(disable:4996)
 15 #pragma comment(linker, "/STACK:1024000000,1024000000")
 16 typedef long long LL;
 17 const int INF = 1<<30;
 18 /*
 19 最大边的权值减去最小边的权值      要最小的生成树,
 20 即树的边权尽可能相近
 21
 22 枚举最小边的权值,然后生成生成树 , 然后计算权值之差,  取取最小的那一个
 23 时间复杂度是m * m * logm  ,
 24
 25
 26 因为生成树是
 27 */
 28 const int N = 350 + 10;
 29 struct Edge
 30 {
 31     int u, v, dis;
 32     bool operator<(const Edge&rhs)
 33     {
 34         return dis < rhs.dis;
 35     }
 36 }g[N*N];
 37 int fa[N];
 38 int find(int x)
 39 {
 40     if (x == fa[x])
 41         return x;
 42     return fa[x] = find(fa[x]);
 43 }
 44 int kruskal(int n, int j ,int m)
 45 {
 46     for (int i = 0; i <= n; ++i)
 47     {
 48         fa[i] = i;
 49     }
 50     int cnt = 0, ret = 0;
 51     for (int i = j; i < m; ++i)
 52     {
 53         int fx = find(g[i].u);
 54         int fy = find(g[i].v);
 55         if (fx != fy)
 56         {
 57             fa[fx] = fy;
 58             if (cnt == 0)
 59                 ret = g[i].dis;
 60             if (cnt != 0 && g[i].dis - ret > ans)
 61                 return -1;
 62             cnt++;
 63             if (cnt == n - 1)
 64                 ret = g[i].dis - ret;
 65         }
 66     }
 67     if (cnt == n - 1)
 68         return ret;
 69     return  -1;
 70 }
 71
 72
 73 int main()
 74 {
 75     //freopen("d:/in.txt", "r", stdin);
 76     int n, m;
 77     while (scanf("%d",&n),n)
 78     {
 79         scanf("%d", &m);
 80         for (int i = 0; i < m; ++i)
 81             scanf("%d%d%d", &g[i].u, &g[i].v, &g[i].dis);
 82         sort(g, g + m);
 83         int ans = kruskal(n, 0 ,m);
 84         if (ans == -1)
 85             puts("-1");
 86         else
 87         {
 88             for (int i = 1; i < m; ++i)
 89             {
 90                 int ret = kruskal(n, i, m);
 91                 if (m - i < n - 1)
 92                     break;
 93                 if (ret != -1)
 94                     ans = min(ans, ret);
 95             }
 96             printf("%d\n", ans);
 97         }
 98     }
 99     return 0;
100 }

时间: 2024-10-13 23:47:51

生成树专题的相关文章

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

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

2017暑假集训前总结和规划

距离大一进来已经一年了啊,感觉还是啥也不会,哎,太差了,总结一下这一年都学了写什么吧! 大一寒假开始专题,刷过的有:dp,dfs和bfs,数论(gcd拓展gcd,欧拉定理等等,但是中国剩余定理没学,等复习的时候再学吧),并查集,最短路(bellman-fprd,dijkstra,floyd-warshall,spfa),最小生成树(prim,kruskal),线段树,二分三分 大一下学期有:拓扑排序,基础计算几何(直线线段相交,快速排除实验,跨立实验),矩阵快速幂,博弈基础(nim博弈,威佐夫博

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

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

[kuangbin带你飞]专题六 生成树

A. POJ 1679  The Unique MST 题意:最小生成树是不是唯一的. 思路:参考http://www.cnblogs.com/onlyAzha/p/4793031.html B. HDU 4081  Qin Shi Huang's National Road System 题意:秦始皇想要在城市之间修路.徐福可以用法力帮助他修一条路.秦始皇希望修一条路使得剩下的路需要的花费B最少,而徐福希望这条路所连的两个城市的人口数之和A最大.权衡后他们决定选择A/B的值最大的边来修建. 思

【生成树计数】专题总结

在CTSC和APIO上好像经常听到生成树计数这东西 于是就去看了下论文 蒟蒻表示看不懂证n明orz 反正懂用就行了.. 生成树计数 生成树计数就是给出一种n个点的无向图G 求这n个点的生成树个数 G的度数矩阵d[i][j] 当i≠j时d[i][j]=0 否则等于i点的度数 G的邻接矩阵a[i][j] a[i][j]=i.j间的边的个数(能有重边) Kirchhoff矩阵 c[i][j]=d[i][j]-a[i][j] Kirchhoff矩阵的n-1阶主子式的行列式的值的绝对值即为生成树的个数 n

计数类问题专题

主要是前两天被uoj的毛爷爷的题虐的不轻,心里很不爽啊,必须努力了,, 计数类问题分为:1.组合数学及数论计数 2.dp:状态压缩dp,插头轮廓线dp,树形dp,数位dp,普通dp 3.容斥原理 4.polya原理 5.图论计数 6.生成函数 7.其它(生成树计数等等) 本文主要研究前3个内容 考虑基本计数原理:加法原理,减法原理,乘法原理,除法原理 计数的基本原则:结果不重不漏 加法原理比较自然,中间过程有时减法原理 考虑到无向,有向图的各种量值(生成树之类)计数,状态压缩dp解决 论文:ht

Kuangbin Flying 6最小生成树专题

先说算法:解释算法思想,可以直接从底下的代码复制作为模版 1.Prim.http://baike.baidu.com/link?url=A_L0v3P9Fqk_cmIGZYzA_hFRSOcCGHF8HYISu8HPjmihFhZ_V22oB3agYXCOYI2dY-SELII_ACQaEh5wK7Bmxq 2.Kruskal.http://baike.baidu.com/view/247951.htm 相信百度百科比我讲得绝对好多了. 图论最主要是建图的思想,然后就是上bin神的模版 A -

正睿OI国庆DAY2:图论专题

正睿OI国庆DAY2:图论专题 dfs/例题 判断无向图之间是否存在至少三条点不相交的简单路径 一个想法是最大流(后来说可以做,但是是多项式时间做法 旁边GavinZheng神仙在谈最小生成树 陈主力说做法是dfs 首先两个点一定在点双联通分量里 点双是简单环,只有两条,不存在 猜测其他情况存在三条 双联通分量分解 输出情况可以用dfs树判,讨论非树边覆盖情况 内包含 下面分叉连到上面 相交 输出点即可 BFS/例题 BFS树没有跳跃边 计数/动态规划有用吧 树上bfs序好像可以判断距离? 边权

「专题总结」线性基

为什么要把毫无关联的线性基和群论放在一个专题里呢..? 因为它们都很毒瘤 线性基本身还是比较简单的,用于处理一些数子集异或和的集合有哪些. 然而它的考察方法总是很神奇... 题目难度大致升序,但是没有前置知识关系: 元素: $Description:$ 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力取决于使用的矿石. 一般地,矿石越多则法力越强,但物极必反:有时,人们为了获取更强的法力而使用了很多矿石,却在炼制