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