D. The Child and Zoo 2

http://codeforces.com/contest/437/problem/D

排序+并查集

为了理解原理,让我们先画一个圈:

其中红边无限大,黑边值为0

我们可以发现,红边的值:1、直接就是f(1,2),2、毫不影响剩下的f(1,3)、f(1,4)、f(2,3)、f(2,4)、f(3,4)的值

所以对应的,我们可以得出:1、当它是图里最大的边时,它的贡献可求,2、球完之后,它唯一的作用就是确保连通性,除此之外就是个摆设

而题目里求所有点对的f()值等价于求所有边对所有点对的贡献

解决1用排序,解决2用并查集

 1 import java.util.Arrays;
 2 import java.util.Scanner;
 3
 4 import static java.lang.Math.min;
 5
 6 public class Main {
 7     static final int MAX = Integer.MAX_VALUE;
 8     static int[] f = new int[100000 + 50];
 9
10     public static void main(String[] args) {
11         Scanner io = new Scanner(System.in);
12         int n = io.nextInt(), m = io.nextInt();
13
14         int[] a = new int[n + 1], c = new int[n + 1];
15         for (int i = 1; i <= n; i++) {
16             a[i] = io.nextInt();
17             f[i] = i;
18             c[i] = 1;
19         }
20
21         P[] ps = new P[m];
22         for (int i = 0, aa, bb; i < m; i++) {
23             aa = io.nextInt();
24             bb = io.nextInt();
25             ps[i] = new P(aa, bb, min(a[aa], a[bb]));
26         }
27
28         Arrays.sort(ps);
29         double w = 0;
30         for (int i = 0, fx, fy, v; i < m; i++) {
31             P p = ps[i];
32             fx = find(p.x);
33             fy = find(p.y);
34             v = p.v;
35             if (fx == fy) continue;
36             //这道题这里和下面非常容易溢出,升double是必须的
37             // 并且1L和1.0【一定】要放在最前面,因为它是一边乘一边检测
38             // 什么时候碰到1.0就什么时候升double
39             w += 1L * v * c[fx] * c[fy];
40             f[fx] = fy;
41             c[fy] += c[fx];
42         }
43         //下面
44         System.out.println(w / (1.0 * n * (n - 1) / 2));
45     }
46
47     static int find(int x) {
48         return f[x] == x ? x : (f[x] = find(f[x]));
49     }
50
51     static class P implements Comparable<P> {
52         int x, y, v;
53
54         public P(int x, int y, int v) {
55             this.x = x;
56             this.y = y;
57             this.v = v;
58         }
59
60         @Override
61         public int compareTo(P o) {
62             return -v + o.v;
63         }
64     }
65 }

原文地址:https://www.cnblogs.com/towerbird/p/11410058.html

时间: 2024-10-13 01:03:32

D. The Child and Zoo 2的相关文章

Codeforces Round #250 (Div. 1) B. The Child and Zoo(排序+并查集)(常规好题)

B. The Child and Zoo time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Of course our child likes walking in a zoo. The zoo has n areas, that are numbered from 1 to n. The i-th area contains 

Codeforces 437D The Child and Zoo(贪心+并查集)

题目链接:Codeforces 437D The Child and Zoo 题目大意:小孩子去参观动物园,动物园分很多个区,每个区有若干种动物,拥有的动物种数作为该区的权值.然后有m条路,每条路的权值为该条路连接的两个区中权值较小的一个.如果两个区没有直接连接,那么f值即为从一个区走到另一个区中所经过的路中权值最小的值做为权值.问,平均两个区之间移动的权值为多少. 解题思路:并查集+贪心.将所有的边按照权值排序,从最大的开始连接,每次连接时计算的次数为连接两块的节点数的积(乘法原理). #in

Codeforces 437 D. The Child and Zoo 并查集

题目链接:D. The Child and Zoo 题意: 题意比较难懂,是指给出n个点并给出这些点的权值,再给出m条边.每条边的权值为该条路连接的两个区中权值较小的一个.如果两个区没有直接连接,那么f值即为从一个区走到另一个区中所经过的路中权值最小的值做为权值.如果有多条路的话,要取最大的值作为路径的长度.问,平均两个区之间移动的权值为多少. 题解: 每条边的长度已经知道了,因为路径的权值取这条路中最小的且多条路的话则取较大的,那么我们其实可以从比较大的边开始取(先把边排序),用并查集开始合并

codeforce 437 D The Child and Zoo

题意:给出n个带权值的点,m条边,任意两点之间的一条路径的权值为这条路径上的所有点中的最小权值,任意两点间的权值为它们之间所有路径的权值中最大的那个. 做法:考虑下并查集,就是首先把所有边降序排序,然后开始建立并查集,若要加入的两点已经在同一个集合中,那么已经贡献到了ans,不用管了,若不在,则进行合并,利用乘法原理也就是两个集合元素数量相乘算出它们之间能够形成多少路径,这些路径的权值就是这两个点的最小权值,然后贡献给ans,不断如此,就可算出答案.还是很有意思的. #include<map>

[CF#250 Div.2 D]The Child and Zoo(并查集)

题目:http://codeforces.com/problemset/problem/437/D 题意:有n个点,m条边的无向图,保证所有点都能互通,n,m<=10^5 每个点都有权值,每条边的权值定义为这条边连接两点的权值中的最小值. f(p,q)表示p到q的路径中边权的最小值,如果有多条路经,就取每条路径最小值中的最小值 要求的就是对于所有1<=p<=n,1<=q<=n,p≠q,f(p,q)的平均值 分析: 刚开始是想考虑每条边对总和的贡献,结果没想通. 一个很巧的办法

D. The Child and Zoo

http://codeforces.com/contest/437/problem/D 贪心,按照自身的费用从大到小拿,费用的相等先后顺序不影响结果 1 import java.util.*; 2 3 public class Main { 4 static final int MAX = Integer.MAX_VALUE; 5 6 public static void main(String[] args) { 7 Scanner io = new Scanner(System.in); 8

Codeforces 437D The Child and Zoo

这个题还是很好的 有几个套路 先是我们看到题目中让我们处理点权,但是我们发现并不好处理 所以就先化点为边 (套路1) 把每一条边的边权视作边所连接的两个点的\(min\)值 然后我们看到这个题有路径的问题,就先还是要较大的 可以比较显然地想到最大生成树 (套路2) 在\(Kruskal\)中改一下排序方式就行了 然后我们看到不是生成树上的边都我们在考虑走的时候都不会考虑 考虑每一个树边的贡献 连接两个联通块的时候 这一条边会产生\(val[edge]* size[x]* size[y]\)的贡献

Codeforces Round #250 (Div. 1)B(排序+并查集)

B. The Child and Zoo time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Of course our child likes walking in a zoo. The zoo has n areas, that are numbered from 1 to n. The i-th area contains 

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734