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.
posted @ 2012-04-25 12:26  F.D.His.D  阅读(283)  评论(0编辑  收藏  举报