Bzoj 1016
题目大意:求可能的最小生成树有多少棵、
解:这个要用一些证明,这里只写自己的一些看完各神牛的blog后的想法总结,证明并不严谨。
首先我们用kruskal求最小生成树的原理是,用权值为c的边把一些强连通分量连起来,然后c从小到大递增,用并查集判可行性。如果反证伪,则在最后一步时,存在比c小的边把强连通分量连起来了,但kruskal的特性不会让这种事情发生。所以可以证明,在第n步,对于 相同的图 来说,如果存在不同的最小生成树,对应的不同只是在第n步选择的边的可能,而设原最小生成树的第n步用的边的大小为c,那么一定有其他最小生成树的第n步,用的边也一定是c,而且使用的边的数量相同,而且连接的强连通分量的点集一定相同(因为不同则从第一步开始,每个强连通分量都是点自己,如果比第一次做的点要多,说明有n-1条树边中,有的边变小了[如原来用a条c边,现在用b条c边,而多出来的b-a在原来的生成树中是大于c的],所以违反了最小生成树的原理,同理可证少了),所以像构建最小生成树一样,从最小的边开始,在权值为c的边中,以2^p枚举可能,用乘法原理相乘即可。
View Code
1 //bzoj 1016 [JSOI2008] zuixiaoshengchengshujishu 2 const 3 maxm=1111; 4 maxn=111; 5 inf='1.txt'; 6 def=31011; 7 type 8 type_edge=record 9 a, b: longint; 10 cost: qword; 11 end; 12 var 13 edge: array[0..maxm]of type_edge; 14 f, f_2:array[0..maxn]of longint; 15 n, m: longint; 16 cnt, ans, key: qword; 17 procedure qsort(b, e: longint); 18 var 19 i, j, x: longint; 20 k: type_edge; 21 begin 22 i := b; j := e; x := edge[(i+j)>>1].cost; 23 repeat 24 while edge[i].cost<x do inc(i); 25 while edge[j].cost>x do dec(j); 26 if i<=j then begin 27 k := edge[i]; edge[i] := edge[j]; edge[j] := k; 28 inc(i); dec(j); 29 end; 30 until i>j; 31 if j>b then qsort(b, j); 32 if i<e then qsort(i, e); 33 end; 34 35 function getf(x: longint): longint; 36 begin 37 if f[x] = x then exit(x); 38 f[x] := getf(f[x]); 39 exit(f[x]); 40 end; 41 42 function getfex(x: longint): longint; 43 begin 44 if x=f_2[x] then exit(x); 45 getfex := getfex(f_2[x]); 46 end; 47 48 procedure init; 49 var 50 i: longint; 51 begin 52 readln(n, m); 53 for i := 1 to m do with edge[i] do readln(a, b, cost); 54 for i := 1 to n do begin 55 f[i] := i; f_2[i] := i; 56 end; 57 qsort(1, m); 58 ans := 1; key := 0; 59 end; 60 61 procedure dfs(st, ed, num: longint); 62 var 63 a, b: longint; 64 begin 65 if num=0 then begin 66 inc(cnt); exit; 67 end; 68 if st>ed then exit; 69 a := getfex(edge[st].a); b := getfex(edge[st].b); 70 if a<>b then begin 71 f_2[a] := b; 72 dfs(st+1, ed, num-1); 73 f_2[a] := a; 74 end; 75 dfs(st+1, ed, num); 76 end; 77 78 function find(st, ed, num: longint): qword; 79 begin 80 cnt := 0; 81 dfs(st, ed, num); 82 if cnt=0 then find := 1 83 else find := cnt; 84 end; 85 86 procedure main; 87 var 88 i, j, now, num, a, b: longint; 89 begin 90 now := 1; num := 0; 91 for i := 1 to m do begin 92 if (i<>1)and(edge[i].cost<>edge[i-1].cost) then begin 93 ans := ans * find(now, i-1, num) mod def; 94 f_2 := f; 95 num := 0; 96 now := i; 97 end; 98 a := getf(edge[i].a); b := getf(edge[i].b); 99 if a<>b then begin 100 inc(key); inc(num); 101 f[a] := b; 102 end; 103 if key=n-1 then break; 104 end; 105 while (i<m)and(edge[i].cost=edge[i+1].cost) do inc(i); 106 ans := ans * find(now, i, num) mod def; 107 end; 108 109 procedure print; 110 begin 111 if key=n-1 then writeln(ans) 112 else writeln(0); 113 end; 114 115 begin 116 assign(input,inf); reset(input); 117 init; 118 main; 119 print; 120 end.