bzoj 1016 kruscal+乘法原理

15 篇文章 0 订阅
11 篇文章 0 订阅

题意:求n个点、m条边的不同的最小生成树的方案数

每种边权的边数量固定、作用固定

先做一遍最小生成树,求出每种边权在最小生成树中的数量num[i]

再从小到大对每种边权进行dfs,求出对于第i种边权,有多少种满足num[i]的取法

根据乘法原理乘上即可

对于已经处理完的第i种边权,把该种边权所有的边能加到最小生成树的就加进去,再进行下一种边权的判断

注意并查集不要用路径压缩,不然不方便分开联通块(不容易还原)

const
        mo=31011;
type
        rec=record
            x,y,len:longint;
end;

type
        rec1=record
             l,r,num:longint;
end;

var
        n,m,tt,tot,tx,ty:longint;
        sum,ans         :longint;
        i,j             :longint;
        l               :array[0..1010] of rec;
        a               :array[0..1010] of rec1;
        father          :array[0..110] of longint;

function get_father(x:longint):longint;
begin
   if x=father[x] then exit(x);
   exit(get_father(father[x]));
end;

procedure sort(ll,rr:longint);
var
        i,j,x:longint;
        y:rec;
begin
   i:=ll; j:=rr; x:=l[(ll+rr)>>1].len;
   while i<=j do
   begin
      while l[i].len<x do inc(i);
      while l[j].len>x do dec(j);
      if i<=j then
      begin
         y:=l[i]; l[i]:=l[j]; l[j]:=y;
         inc(i); dec(j);
      end;
   end;
   if i<rr then sort(i,rr);
   if j>ll then sort(ll,j);
end;

procedure dfs(x,now,num:longint);
var
        tx,ty:longint;
begin
   if now=a[x].r+1 then
   begin
      if num=a[x].num then inc(sum); exit;
   end;
   tx:=get_father(l[now].x);
   ty:=get_father(l[now].y);
   if tx<>ty then
   begin
      father[tx]:=ty;
      dfs(x,now+1,num+1);
      father[tx]:=tx;
   end;
   dfs(x,now+1,num);
end;

begin
   read(n,m);
   for i:=1 to m do read(l[i].x,l[i].y,l[i].len);
   sort(1,m);
   tt:=0; tot:=0;
   for i:=1 to n do father[i]:=i;
   for i:=1 to m do
   begin
      if l[i].len<>l[i-1].len then
      begin
         inc(tot); a[tot].l:=i; a[tot-1].r:=i-1;
      end;
      tx:=get_father(l[i].x);
      ty:=get_father(l[i].y);
      if tx<>ty then
      begin
         father[tx]:=ty;
         inc(tt);
         inc(a[tot].num);
      end;
   end;
   a[tot].r:=m;
   if tt<>n-1 then
   begin
      writeln(0); exit;
   end;
   //
   ans:=1;
   for i:=1 to n do father[i]:=i;
   for i:=1 to tot do
   begin
      sum:=0;
      dfs(i,a[i].l,0);
      ans:=(ans*sum) mod mo;
      for j:=a[i].l to a[i].r do
      begin
         tx:=get_father(l[j].x);
         ty:=get_father(l[j].y);
         if tx<>ty then father[tx]:=ty;
      end;
   end;
   writeln(ans);
end.
——by Eirlys

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值