bzoj1016 JSOI2008 最小生成樹計數

2022-05-31 08:36:11 字數 3472 閱讀 1512

現在給出了乙個簡單無向加權圖。你不滿足於求出這個圖的最小生成樹,而希望知道這個圖中有多少個不同的最小生成樹。(如果兩顆最小生成樹中至少有一條邊不同,則這兩個最小生成樹就是不同的)。由於不同的最小生成樹可能很多,所以你只需要輸出方案數對31011的模就可以了。

第一行包含兩個數,n和m,其中1<=n<=100; 1<=m<=1000; 表示該無向圖的節點數和邊數。每個節點用1~n的整數編號。接下來的m行,每行包含兩個整數:a, b, c,表示節點a, b之間的邊的權值為c,其中1<=c<=1,000,000,000。資料保證不會出現自回邊和重邊。注意:具有相同權值的邊不會超過10條。

輸出不同的最小生成樹有多少個。你只需要輸出數量對31011的模就可以了。

4 61 2 1

1 3 1

1 4 1

2 3 2

2 4 1

3 4 1

8誒這題不大好理解。

直接把題解複製上來啦:

發現最小生成樹的形態是固定的。

即如果有一顆最小生成樹,則所有最小生成樹所使用的相同權值的邊的數量是一樣的,並且每次構出的點都是一樣的。

就是說每次都是相同的點被相同權值的邊給連線起來。這個簡單的證明就是如果有不同權值的邊連上的相同的點,那麼一定會有更優的生成樹。

於是知道了這兩個性質這題就很好搞了,排序之後先做一遍最小生成樹,得出了每種權值所用的邊的數量,然後打乙個大暴力,列舉相同權值的邊,然後並查集暴力判環,得出某種邊權值的邊的選擇方案,然後乘法原理統計答案,組合數效率,因為相同權值的邊最多有10條,所以最壞效率是20個c(10,5),發現效率是很ok的,如果不用並查集判環,複雜度就是滿的,判環相當於大量剪枝,於是發現實際上暴力根本達不到滿複雜度的效率,大量資料直接0.015s秒出。

p.s. 請注意判沒有生成樹的情況。

1

program

award(input,output);

2const

3 cs=31011;4

var5 father:array[0..110]of

longint;

6 a,b,w,l,r,num:array[0..1010]of

longint;

7n,m,i,j,cnt,x,y,ans:longint;

8procedure

sort(q,h:longint);

9var

10i,j,x,t:longint;

11begin

12 i:=q;j:=h;x:=w[(i+j)>>1

];13

repeat

14while w[i]do

inc(i);

15while xdo

dec(j);

16if i<=j then

17begin

18 t:=a[i];a[i]:=a[j];a[j]:=t;

19 t:=b[i];b[i]:=b[j];b[j]:=t;

20 t:=w[i];w[i]:=w[j];w[j]:=t;

21inc(i);dec(j);

22end;23

until i>j;

24if j>q then

sort(q,j);

25if ithen

sort(i,h);

26end;27

function

find(k:longint):longint;

28begin

29if father[k]=k then exit(k) else

exit(find(father[k]));

30end;31

procedure

dfs(k,s:longint);

32var

33x,y:longint;

34begin

35if k=r[i]+1

then

begin

if s=num[i] then inc(j);exit; end

;36 x:=find(a[k]);y:=find(b[k]);

37if x<>y then

38begin

39 father[x]:=y;

40 dfs(k+1,s+1

);41 father[x]:=x;

42end

;43 dfs(k+1

,s);

44end;45

begin

46 assign(input,'

award.in

');assign(output,'

award.out

');reset(input);rewrite(output);

47readln(n,m);

48for i:=1

to m do

readln(a[i],b[i],w[i]);

49 sort(1

,m);

50for i:=1

to n do father[i]:=i;

51 w[0]:=0;j:=0;cnt:=0

;52 fillchar(num,sizeof(num),0

);53

for i:=1

to m do

54begin

55if w[i]<>w[i-1] then

begin r[cnt]:=i-1;inc(cnt);l[cnt]:=i; end

;56 x:=find(a[i]);y:=find(b[i]);

57if x<>y then

begin father[x]:=y;inc(num[cnt]);inc(j); end;58

end;

59 r[cnt]:=m;

60if j1

then

begin write(0);close(input);close(output);halt; end

;61 ans:=1;62

for i:=1

to n do father[i]:=i;

63for i:=1

to cnt do

64begin

65 j:=0

;66 dfs(l[i],0

);67 ans:=ans*j mod

cs;68

for j:=l[i] to r[i] do

69begin

70 x:=find(a[j]);y:=find(b[j]);

71if x<>y then father[x]:=y;

72end;73

end;

74write(ans);

75close(input);close(output);

76end.

bzoj1016 JSOI2008 最小生成樹計數

description 現在給出了乙個簡單無向加權圖。你不滿足於求出這個圖的最小生成樹,而希望知道這個圖中有多少個不同的 最小生成樹。如果兩顆最小生成樹中至少有一條邊不同,則這兩個最小生成樹就是不同的 由於不同的最小生 成樹可能很多,所以你只需要輸出方案數對31011的模就可以了。input 第一行...

bzoj 1016 kruscal 乘法原理

題意 求n個點 m條邊的不同的最小生成樹的方案數 每種邊權的邊數量固定 作用固定 先做一遍最小生成樹,求出每種邊權在最小生成樹中的數量num i 再從小到大對每種邊權進行dfs,求出對於第i種邊權,有多少種滿足num i 的取法 根據乘法原理乘上即可 對於已經處理完的第i種邊權,把該種邊權所有的邊能...

1016 JSOI2008 最小生成樹計數

description 現在給出了乙個簡單無向加權圖。你不滿足於求出這個圖的最小生成樹,而希望知道這個圖中有多少個不同的 最小生成樹。如果兩顆最小生成樹中至少有一條邊不同,則這兩個最小生成樹就是不同的 由於不同的最小生 成樹可能很多,所以你只需要輸出方案數對31011的模就可以了。input 第一行...