題目:
鄉下有n(n<=8)個小村莊,用m條雙向道路串連起來,每兩個村莊最多用一條道路直接連接。最近村莊鬧澇災,洪水讓這些道路各有一定的機率被淹沒,而這些道路被淹沒與否是相互獨立的。你的任務是計算出所有村莊連在一起(即:從任意一個村莊都可以經過未被淹沒的道路到達其他所有村莊)的機率有多大。
分析:n=8,顯然不是裸搜就是狀態壓縮dp,裸搜顯然也是很難過的,那麼本題的方向就出來了
演算法:
記f[i]表示i這個狀態中所有的點連通的機率,如果直接把要選的點分成2個集合什麼的做法是會算重的
而為了避免算重,我們需要規定一些東西,比方說可以這樣規定:先孤立出所選集合中的第一個點,然後枚舉其他點的連通情況,且其他點形成的連通塊之間不能直接相連,只能和這個孤立出的點相連,
裡面需要套一個搜其他點連通情況的dfs,驚奇發現大過程套小過程,小過程還可以調用大過程,而且大過程的局部變數是小過程的全程變數,只是debug的時候監控不了,使我鬱悶好久,考完才想到解決辦法。。
大部分機率計算都比較飄,這題也不例外,我差不多花了一個多小時才曉得範例是怎麼搞的。。。
這題資料規模真是小,我這個O(2^n*n!*n^2)居然全0ms啦,哈哈。
program syj; {dp}<br />var n,m,all,i,j,k,k1,k2:longint;<br /> a:array[1..8,1..8]of real;<br /> f:array[0..1<<8]of real;<br /> bb:array[0..8]of real;<br /> g:array[1..8,1..8]of boolean;<br />procedure dfs(i:longint);<br />var jj:longint;<br /> b:array[0..8]of longint;<br /> procedure find(j,k:longint);<br /> var l,ll,lj,lk:longint; t1,t2:real;<br /> begin<br /> if j=0 then begin<br /> t1:=1;<br /> for l:=1 to b[0] do bb[l]:=b[l];<br /> for l:=1 to b[0] do begin<br /> dfs(b[l]);<br /> j:=b[l];ll:=1;t2:=1;<br /> while j>0 do begin<br /> if odd(j) then t2:=t2*a[jj,ll];<br /> j:=j>>1;inc(ll);<br /> end;<br /> t1:=t1*(1-t2)*f[b[l]];<br /> end;<br /> for l:=1 to b[0]-1 do<br /> for ll:=l+1 to b[0] do begin<br /> j:=b[l];lj:=1;t2:=1;<br /> while j>0 do begin<br /> if odd(j) then begin<br /> k:=b[ll];lk:=1;<br /> while k>0 do begin<br /> if odd(k) then t2:=t2*a[lj,lk];<br /> k:=k>>1;inc(lk);<br /> end;<br /> end;<br /> j:=j>>1;inc(lj);<br /> end;<br /> t1:=t1*t2;<br /> end;<br /> f[i]:=f[i]+t1;<br /> exit;<br /> end;<br /> while not odd(j) do begin<br /> j:=j>>1;inc(k);<br /> end;<br /> for l:=1 to b[0] do begin<br /> ll:=b[l];b[l]:=b[l] or(1<<(k-1));<br /> find(j>>1,k+1);<br /> b[l]:=ll;<br /> end;<br /> inc(b[0]);b[b[0]]:=1<<(k-1);<br /> find(j>>1,k+1);<br /> b[b[0]]:=0;dec(b[0]);<br /> end;<br />begin<br /> if f[i]>-1 then exit; f[i]:=0;<br /> for jj:=1 to n do if odd(i>>(jj-1)) then break;<br /> b[0]:=0;<br /> find(i xor(1<<(jj-1)),1);<br />end;<br />begin<br /> assign(input,'flood.in');reset(input);<br /> assign(output,'flood.out');rewrite(output);<br /> readln(n,m); all:=(1<<n)-1;<br /> for i:=1 to n do<br /> for j:=1 to n do a[i,j]:=1;<br /> for i:=1 to m do begin<br /> readln(j,k,a[j,k]);a[k,j]:=a[j,k];<br />// a[j,k]:=1-a[j,k];a[k,j]:=1-a[k,j];<br /> end;<br /> for i:=1 to all do f[i]:=-2;<br /> for i:=1 to n do f[1<<(i-1)]:=1;<br /> dfs(all);<br /> {for i:=1 to n do<br /> for j:=i+1 to n do if a[i,j]>1e-8 then<br /> for k1:=1 to all-1 do if odd(k1>>(i-1)) then<br /> for k2:=1 to all-1 do if odd(k2>>(j-1))and(k1 and k2=0) then<br /> f[k1 or k2]:=f[k1 or k2]+f[k1]*f[k2]*a[i,j];}<br /> writeln(f[all]:0:3);<br /> close(input);<br /> close(output);<br />end.<br />