1016: [JSOI2008]最小生成树计数 - BZOJ

Description

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。
Input

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。
Output

输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
Sample Input
4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1


Sample Output
8

 

网上的题解基本上没有证明(或许有,但是我没看见,然后懒得找了)

两个最小生成树的权值相同的边作用相同(连通情况)

我们可以用反证法

假设有两个最小生成树的权值相同的边作用不同,那么把最小的作用不同的权值找出来

然后我们把他们的连通情况合并(去环),需要的边肯定会变多,而且一定可以做到,相当于我们用多出来的边代替了权值比它大的边,那这与前面说的这是最小生成树矛盾

例:假设权值为1的边在一棵最小生成树里造成连通情况是(1,2)(3,4),在另一棵最小生成树里造成的连通情况是(1,4)(2,3)

那我们可以合并它们用权值为1的边做到(1,2,3,4),来替换一条权值大于1的边,得到一颗权值更小的树

证毕.

所以我们记录每种权值的边所造成的连通情况记录下来,每个权值做一遍,乘起来就是答案(注意判断无解的情况)

 

  1 const

  2     maxn=105;

  3     maxm=1010;

  4     h=31011;

  5 var

  6     ans,n,m,l:longint;

  7     u,v,w:array[0..maxm]of longint;

  8     a:array[0..10,0..1024]of longint;

  9  

 10 procedure swap(var x,y:longint);

 11 var

 12     t:longint;

 13 begin

 14     t:=x;x:=y;y:=t;

 15 end;

 16  

 17 procedure sort(l,r:longint);

 18 var

 19     i,j,y:longint;

 20 begin

 21     i:=l;

 22     j:=r;

 23     y:=w[(l+r)>>1];

 24     repeat

 25       while w[i]<y do

 26         inc(i);

 27       while w[j]>y do

 28         dec(j);

 29       if i<=j then

 30       begin

 31         swap(u[i],u[j]);

 32         swap(v[i],v[j]);

 33         swap(w[i],w[j]);

 34         inc(i);

 35         dec(j);

 36       end;

 37     until i>j;

 38     if i<r then sort(i,r);

 39     if j>l then sort(l,j);

 40 end;

 41  

 42 function bit(x:longint):longint;

 43 begin

 44     if x=0 then exit(0);

 45     exit(bit(x-(x and -x))+1);

 46 end;

 47  

 48 procedure init;

 49 var

 50     i,k:longint;

 51 begin

 52     read(n,m);

 53     for i:=1 to m do

 54       read(u[i],v[i],w[i]);

 55     sort(1,m);

 56     for i:=0 to 1023 do

 57       begin

 58         k:=bit(i);

 59         inc(a[k,0]);

 60         a[k,a[k,0]]:=i;

 61       end;

 62 end;

 63  

 64 var

 65     f,f2,vis:array[0..maxn]of longint;

 66     xu:array[0..maxm]of longint;

 67     time:longint;

 68  

 69 function find(x:longint):longint;

 70 begin

 71     if vis[x]<>time then

 72     begin

 73       f[x]:=f2[x];

 74       vis[x]:=time;

 75     end;

 76     if f[x]=x then exit(x);

 77     f[x]:=find(f[x]);

 78     exit(f[x]);

 79 end;

 80  

 81 function find2(x:longint):longint;

 82 begin

 83     if f2[x]=x then exit(x);

 84     f2[x]:=find2(f2[x]);

 85     exit(f2[x]);

 86 end;

 87  

 88 function flag(x:longint):boolean;

 89 var

 90     i:longint;

 91 begin

 92     i:=0;

 93     while x>0 do

 94       begin

 95         inc(i);

 96         if x and 1=1 then

 97         begin

 98           if find(u[l+i])=find(v[l+i]) then exit(false);

 99           if (f[u[l+i]]<>f[v[l+i]])and(find2(u[l+i])=find2(v[l+i])) then exit(false);

100           f[f[u[l+i]]]:=f[v[l+i]];

101         end;

102         x:=x>>1;

103       end;

104     exit(true);

105 end;

106  

107 procedure work;

108 var

109     i,j,s,last:longint;

110 begin

111     ans:=1;

112     for i:=1 to n do

113       f2[i]:=i;

114     for i:=1 to m do

115       begin

116         if w[i]=w[i-1] then xu[i]:=xu[i-1];

117         if find2(u[i])<>find2(v[i]) then

118         begin

119           inc(xu[i]);

120           f2[f2[u[i]]]:=f2[v[i]];

121         end;

122       end;

123     for i:=1 to n-1 do

124       if find2(i)<>find2(i+1) then ans:=0;

125     for i:=1 to n do

126       f2[i]:=i;

127     l:=0;

128     last:=0;

129     for i:=1 to m do

130       if w[i]<>w[i+1] then

131       begin

132         s:=0;

133         while last<l do

134           begin

135             inc(last);

136             f2[find2(u[last])]:=find2(v[last]);

137           end;

138         for j:=1 to a[xu[i],0] do

139           begin

140             if a[xu[i],j]>=1<<(i-l) then break;

141             inc(time);

142             if flag(a[xu[i],j]) then inc(s);

143           end;

144         l:=i;

145         ans:=ans*s mod h;

146       end;

147     write(ans);

148 end;

149  

150 begin

151     init;

152     work;

153 end.
View Code

 

你可能感兴趣的:(最小生成树)