hdu4750Count The Pairs(最小生成树找瓶颈边)

 1 /*
 2    题意:就是给你一个图,图的每两个点都有多条路径,每一条路径中都有一条最大边,
 3    所有最大边的最小边(也就是瓶颈边)就是这两点之间的val值!然后给你一个值f,
 4    问有多少个顶点对的val>=f! (u,v) 和 (v, u)是不同的顶点对!
 5
 6    思路:最小生成树(kruskral)那么每两个节点(u,v)的瓶颈边就是这一棵树中u到v
 7          的路径中的最大边值!
 8          在利用并查集的过程中,A, B两个集合,如果有u属于A,v属于B,且u-v可以将
 9          A-B集合连接起来,因为边值由小到大选取,那么以u-v边为瓶颈边的节点的个数
10          就是[A]*[B]*2;
11
12    注意:图不一定是连通的,开始的时候当成了一棵树,怎么改都不对!
13 */
14 #include<iostream>
15 #include<cstring>
16 #include<cstdio>
17 #include<algorithm>
18 #define N 10105
19 #define M 500105
20 using namespace std;
21 int f[N];
22 struct Edge{
23     int u, v, w;
24     Edge(){}
25     Edge(int u, int v, int w){
26         this->u=u;
27         this->v=v;
28         this->w=w;
29     }
30 };
31
32 Edge edge[M];
33 int dist[N];
34 int rank[N];
35 int cnt[N];
36 int edgeN;
37 int sumN[N];
38 int n, m;
39
40 bool cmp(Edge a, Edge b){
41    return a.w < b.w;
42 }
43
44 int getFather(int x){
45    return x==f[x] ? x : f[x]=getFather(f[x]);
46 }
47
48 bool Union(int a, int b){
49    a=getFather(a);
50    b=getFather(b);
51    if(a!=b){
52       cnt[++edgeN]=sumN[a]*sumN[b]*2;//记录以这一条边为瓶颈边的节点对的个数
53       if(rank[a]>rank[b]){
54           f[b]=a;
55           sumN[a]+=sumN[b];//将b集合放入到a集合中去
56       }
57       else{
58          f[a]=b;
59          sumN[b]+=sumN[a];//将a集合放入到b集合中去
60          ++rank[b];
61       }
62       return true;
63    }
64    return false;
65 }
66
67 void Kruskral(){
68    edgeN=0;
69    sort(edge, edge+m, cmp);
70    for(int i=1; i<=n; ++i)
71       f[i]=i, rank[i]=0, sumN[i]=1;
72    for(int i=0; i<m; ++i)
73     if(Union(edge[i].u, edge[i].v))
74        dist[edgeN]=edge[i].w;//记录最小生成树中的边值
75    cnt[edgeN+1]=0;
76    for(int i=edgeN; i>=1; --i)//统计大于等于第i条边为瓶颈边边值的所有节点对的对数
77        cnt[i]+=cnt[i+1];
78 }
79
80 int main(){
81     int p;
82     while(scanf("%d%d", &n, &m)!=EOF){
83         for(int i=0; i<m; ++i){
84            int u, v, w;
85            scanf("%d%d%d", &u, &v, &w);
86            edge[i]=Edge(u+1, v+1, w);
87         }
88         Kruskral();
89         scanf("%d", &p);
90         while(p--){
91            int x;
92            scanf("%d", &x);
93            int index=lower_bound(dist+1, dist+edgeN+1, x)-dist;
94            if(index>edgeN) printf("0\n");
95            else printf("%d\n", cnt[index]);
96         }
97     }
98     return 0;
99 }
//如果最后只有一棵树的话,这样做就可以了!没想到可能不是仅仅一棵树 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define N 10105
 6 #define M 500105
 7 using namespace std;
 8 int f[N];
 9 struct Edge{
10     int u, v, w;
11     Edge(){}
12     Edge(int u, int v, int w){
13         this->u=u;
14         this->v=v;
15         this->w=w;
16     }
17 };
18
19 Edge edge[M];
20 int dist[N];
21 int rank[N];
22 int cnt[N];
23 int edgeN;
24
25 int n, m;
26
27 bool cmp(Edge a, Edge b){
28    return a.w < b.w;
29 }
30
31 int getFather(int x){
32    return x==f[x] ? x : f[x]=getFather(f[x]);
33 }
34
35 bool Union(int a, int b){
36    a=getFather(a);
37    b=getFather(b);
38    if(a!=b){
39       if(rank[a]>rank[b])
40           f[b]=a;
41       else{
42          f[a]=b;
43          ++rank[b];
44       }
45       return true;
46    }
47    return false;
48 }
49
50 void Kruskral(){
51    edgeN=0;
52    sort(edge, edge+m, cmp);
53    for(int i=1; i<=n; ++i)
54       f[i]=i, rank[i]=0;
55    for(int i=0; i<m; ++i)
56      if(Union(edge[i].u, edge[i].v))
57         dist[++edgeN]=edge[i].w;
58    cnt[edgeN+1]=0;
59    for(int i=edgeN; i>=1; --i){
60        cnt[i]=i*2;
61        cnt[i]+=cnt[i+1];
62    }
63 }
64
65 int main(){
66     int p;
67     while(scanf("%d%d", &n, &m)!=EOF){
68         for(int i=0; i<m; ++i){
69            int u, v, w;
70            scanf("%d%d%d", &u, &v, &w);
71            edge[i]=Edge(u+1, v+1, w);
72         }
73         Kruskral();
74         scanf("%d", &p);
75         while(p--){
76            int x;
77            scanf("%d", &x);
78            int index=lower_bound(dist+1, dist+edgeN+1, x)-dist;
79            if(index>edgeN) printf("0\n");
80            else printf("%d\n", cnt[index]);
81         }
82     }
83     return 0;
84 }
时间: 2024-10-27 12:20:37

hdu4750Count The Pairs(最小生成树找瓶颈边)的相关文章

hdu 4750 Count The Pairs 最小生成树

题意就是给出一个f值,然后假如两个点u,v间的所有路径上的最大边中的最小值大于f,那么这个点对是合法的,对于每个询问f,输出有多少个合法点对. 最大边最小就是最小瓶颈路,即最小生成树上的路径.一个简单的想法就是求出最小生成树后,n次dfs求出任意两点间的最大边,然后对于每个询问再查找一遍,可是时间复杂度太高.再想想的话会发现,两点间生成树上的最大边就是在克鲁斯卡尔的过程中使得他们第一次联通的那条边,所以,每加进一条边,以该边为最大边的点对就是他连接的两个集合的点对. #include <cstd

HDU 4081Qin Shi Huang&amp;#39;s National Road System(最小生成树+最小瓶颈路)

 题意:秦始皇要修路.把N个城市用N-1条边连通.且他希望花费最小,可是这时候有一个多管闲事的道士出来说他有魔法能够帮助秦始皇变成一条路.可是仅仅能变出一条. 可是.两个人对修路的法案存在歧义,道士希望修路能够给很多其它的百姓带来福利.而秦始皇希望修路要尽量使花费小.最后,秦始皇拿出了一个公式A/B.A表示两个城市的人数,B表示出了用魔法变出来的路外.最短的总距离. 如今要你求出A/B的最大值. 思路:枚举连接哪两个城市.由于这条边是免费的.我们要求算上这条边的最小生成树.假设每次都求一次最

UVA - 11354 Bond(最小生成树+LCA+瓶颈路)

题意:N个点,M条路,每条路的危险度为路上各段中最大的危险度.多组询问,点s到点t的所有路径中最小的危险度. 分析: 1.首先建个最小生成树,则s到t的路径一定是危险度最小的. 原因:建最小生成树的最后一步,如果有两个相等的边可以选择,然后将两个连通块连在一起. 那不管选择哪个边,对于分别位于两个连通块的两点来说,这条边都是必经之路,而这个必经之路是这两点路径的危险度中最大的,起决定作用,所以选哪个是一样的. 2.利用lca,在找s和t最近公共祖先的过程中,不断取两者路径中的最大危险度即可. 3

(最小生成树/最小瓶颈生成树) 2017武汉现场赛 - Wifi Relay

题意: n个无线AP,有xy坐标属性,现在n个无线AP要桥接在一起不能断开连接,现在要求无线AP无线网络的覆盖半径最小是多少 分析: 看起来是像是最小生成树,这里是是求生成树中最长的边最短,就是最小瓶颈生成树. 可以证明最小瓶颈生成树就是最小生成树,详细看刘汝佳<算法入门经典训练指南>343页. 当时现场的时候,想试试最小生成树了,结果以为n方复杂度过不去,就没写,现在想起来,真是坑哦. 这题n有10000,所以不能直接建邻接矩阵,而是采用动态计算距离就行了. 比赛结束了随便一写就A了...

算法导论思考题 - 瓶颈生成树

列思路,以后填坑. a. 证明:最小生成树是瓶颈生成树 证略 b. 给定图G和整数b,线性时间内判断瓶颈生成树T值是否不超过b 解:DFS或BFS遍历图G,跳过所有权值大于b的边,最后若有节点未遍历到,则T值大于b,否则不超过b c. 求瓶颈生成树T值 1. 求出边权值的中位数(类似于求nth element一类问题)M,以此将图G的边按权值分成两部分,一部分小于等于M,另一部分大于M 2. 利用b提出的方法判断图G瓶颈生成树的T值是否不超过M,也就是看这个T值位于大小哪半边 3. 若位于小半边

图解最小生成树 - 克鲁斯卡尔(Kruskal)算法

我们在前面讲过的<克里姆算法>是以某个顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树的.同样的思路,我们也可以直接就以边为目标去构建,因为权值为边上,直接找最小权值的边来构建生成树也是很自然的想法,只不过构建时要考虑是否会形成环而已,此时我们就用到了图的存储结构中的边集数组结构,如图7-6-7 假设现在我们已经通过邻接矩阵得到了边集数组edges并按权值从小到大排列如上图. 下面我们对着程序和每一步循环的图示来看: 算法代码:(改编自<大话数据结构>) C++ Code 1

P2502 [HAOI2006]旅行 - 最小生成树【最小比值生成树(雾】

P2502 [HAOI2006]旅行 Sol: 暴力 枚举所有从S到T的路径,然后用maxw/minw更新答案. 时间复杂度:\(O(玄学)\) 正解 观察到边数\(m\leq5000\) 考虑由直接求maxw和minw -> 枚举minw求maxw 由于从S到T的路径上的最大值最小的边一定在最小生成树上(最小生成树的瓶颈路性质),所以我们可以将边从小到大排序,每次枚举边\(e_i\),并将剩下的\(e_i,e_{i+1}\dots e_m\)建最小生成树,当边\(e_k\)使S和T第一次连通时

正睿OI国庆DAY2:图论专题

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

Java 线程的状态

Java Thread的运行周期中, 有几种状态, 在 java.lang.Thread.State 中有详细定义和说明: NEW 状态是指线程刚创建, 尚未启动 RUNNABLE 状态是线程正在正常运行中, 当然可能会有某种耗时计算/IO等待的操作/CPU时间片切换等, 这个状态下发生的等待一般是其他系统资源, 而不是锁, Sleep等 BLOCKED  这个状态下, 是在多个线程有同步操作的场景, 比如正在等待另一个线程的synchronized 块的执行释放, 或者可重入的 synchro