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的边,得到一颗权值更小的树

证毕.

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

 const
maxn=;
maxm=;
h=;
var
ans,n,m,l:longint;
u,v,w:array[..maxm]of longint;
a:array[..,..]of longint; procedure swap(var x,y:longint);
var
t:longint;
begin
t:=x;x:=y;y:=t;
end; procedure sort(l,r:longint);
var
i,j,y:longint;
begin
i:=l;
j:=r;
y:=w[(l+r)>>];
repeat
while w[i]<y do
inc(i);
while w[j]>y do
dec(j);
if i<=j then
begin
swap(u[i],u[j]);
swap(v[i],v[j]);
swap(w[i],w[j]);
inc(i);
dec(j);
end;
until i>j;
if i<r then sort(i,r);
if j>l then sort(l,j);
end; function bit(x:longint):longint;
begin
if x= then exit();
exit(bit(x-(x and -x))+);
end; procedure init;
var
i,k:longint;
begin
read(n,m);
for i:= to m do
read(u[i],v[i],w[i]);
sort(,m);
for i:= to do
begin
k:=bit(i);
inc(a[k,]);
a[k,a[k,]]:=i;
end;
end; var
f,f2,vis:array[..maxn]of longint;
xu:array[..maxm]of longint;
time:longint; function find(x:longint):longint;
begin
if vis[x]<>time then
begin
f[x]:=f2[x];
vis[x]:=time;
end;
if f[x]=x then exit(x);
f[x]:=find(f[x]);
exit(f[x]);
end; function find2(x:longint):longint;
begin
if f2[x]=x then exit(x);
f2[x]:=find2(f2[x]);
exit(f2[x]);
end; function flag(x:longint):boolean;
var
i:longint;
begin
i:=;
while x> do
begin
inc(i);
if x and = then
begin
if find(u[l+i])=find(v[l+i]) then exit(false);
if (f[u[l+i]]<>f[v[l+i]])and(find2(u[l+i])=find2(v[l+i])) then exit(false);
f[f[u[l+i]]]:=f[v[l+i]];
end;
x:=x>>;
end;
exit(true);
end; procedure work;
var
i,j,s,last:longint;
begin
ans:=;
for i:= to n do
f2[i]:=i;
for i:= to m do
begin
if w[i]=w[i-] then xu[i]:=xu[i-];
if find2(u[i])<>find2(v[i]) then
begin
inc(xu[i]);
f2[f2[u[i]]]:=f2[v[i]];
end;
end;
for i:= to n- do
if find2(i)<>find2(i+) then ans:=;
for i:= to n do
f2[i]:=i;
l:=;
last:=;
for i:= to m do
if w[i]<>w[i+] then
begin
s:=;
while last<l do
begin
inc(last);
f2[find2(u[last])]:=find2(v[last]);
end;
for j:= to a[xu[i],] do
begin
if a[xu[i],j]>=<<(i-l) then break;
inc(time);
if flag(a[xu[i],j]) then inc(s);
end;
l:=i;
ans:=ans*s mod h;
end;
write(ans);
end; begin
init;
work;
end.

1016: [JSOI2008]最小生成树计数 - BZOJ的更多相关文章

  1. BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...

  2. 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)

    1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...

  3. 1016: [JSOI2008]最小生成树计数

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 6200  Solved: 2518[Submit][St ...

  4. [BZOJ]1016 JSOI2008 最小生成树计数

    最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...

  5. 【BZOJ】1016: [JSOI2008]最小生成树计数 深搜+并查集

    最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小 ...

  6. [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】

    题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...

  7. 【BZOJ】1016: [JSOI2008]最小生成树计数(kruskal+特殊的技巧)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1016 想也想不到QAQ 首先想不到的是:题目有说,具有相同权值的边不会超过10条. 其次:老是去想组 ...

  8. BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)

    题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...

  9. bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 就是缩点,每次相同权值的边构成的联通块求一下matrix tree.注意gauss里的 ...

随机推荐

  1. MyBatis(3.2.3) - Integration with Spring

    MyBatis-Spring is a submodule of the MyBatis framework, which provides seamless integration with the ...

  2. Linux 命令 - ping: 向网络主机发送 ICMP ECHO_REQUEST 包

    ping 命令会向指定的网络主机发送特殊网络数据报 IMCP ECHO_REQUEST.多数网络设备收到该数据包后会做出回应,通过此法即可验证网络连接是否正常. 有时从安全角度出发,通常会配置部分网络 ...

  3. 函数 datediff(根据objid 获取同name 同年度最近的4条记录)

    显示 包括选择的这条,在加上 选择年度的此人 最近的 3条.(最多显示4条) . 记录数大于4条 . 全显示 create table temp( objid ,) primary key , nam ...

  4. 学习Learn Python The Hard Way 前言中的一段话,可与君共勉

    在你通过这本书学习编程时,我正在学习弹吉他.我每天至少训练 2 小时,至少花一个小时练习音阶.和声.和琶音,剩下的时间用来学习音乐理论和歌曲演奏以及训练听力等.有时我一天会花 8 个小时来练习,因为我 ...

  5. mysql绿色版在windows系统中的启动

    mysql绿色版在windows系统中的启动 1.下载mysql免安装版 例如:mysql-5.7.11-winx64 2.修改配置文件,my-default.ini名称改为:my.ini,文件里面的 ...

  6. 第四篇、微信小程序-icon组件

    属性: 效果图: test.wxml <!--成功图标--> <icon type="success" size="40"/> < ...

  7. gdb/valgrind/coredump to debug c/cpp program

    gdb/valgrind/coredump 调试 1.gdb 调试 while/for 循环 ①如果在调试 while/for的时候,可以用until xxx(其中,xxx代表 行号)直接跳转到循环后 ...

  8. mysql的时间函数

    from_unixtime()是MySQL里的时间函数 date为需要处理的参数(该参数是Unix 时间戳),可以是字段名,也可以直接是Unix 时间戳字符串 后面的 '%Y%m%d' 主要是将返回值 ...

  9. Angularjs在线编辑器

    1.TextAngular: https://github.com/fraywing/textAngular textAngular是一个强大的Text-Editor/Wysiwyg 编辑器,用于An ...

  10. asp.net 时间比较,常用于在某段时间进行操作

    DateTime.Compare(t1,t2)比较两个日期大小,排前面的小,排在后面的大,比如:2011-2-1就小于2012-3-2返回值小于零:  t1 小于 t2. 返回值等于零 : t1 等于 ...