現在給出了乙個簡單無向加權圖。你不滿足於求出這個圖的最小生成樹,而希望知道這個圖中有多少個不同的最小生成樹。(如果兩顆最小生成樹中至少有一條邊不同,則這兩個最小生成樹就是不同的)。由於不同的最小生成樹可能很多,所以你只需要輸出方案數對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. 請注意判沒有生成樹的情況。
1program
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 第一行...