bzoj2560串珠子 狀壓dp+容斥(?)
阿新 • • 發佈:2017-12-13
ng- 劃分 discus day set 串珠子 def color efi
Submit: 515 Solved: 348
[Submit][Status][Discuss]
2560: 串珠子
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 515 Solved: 348
[Submit][Status][Discuss]
Description
銘銘有n個十分漂亮的珠子和若幹根顏色不同的繩子。現在銘銘想用繩子把所有的珠子連接成一個整體。
現在已知所有珠子互不相同,用整數1到n編號。對於第i個珠子和第j個珠子,可以選擇不用繩子連接,或者在ci,j根不同顏色的繩子中選擇一根將它們連接。如果把珠子看作點,把繩子看作邊,將所有珠子連成一個整體即為所有點構成一個連通圖。特別地,珠子不能和自己連接。
銘銘希望知道總共有多少種不同的方案將所有珠子連成一個整體。由於答案可能很大,因此只需輸出答案對1000000007取模的結果。
Input
標準輸入。輸入第一行包含一個正整數n,表示珠子的個數。接下來n行,每行包含n個非負整數,用空格隔開。這n行中,第i行第j個數為ci,j。
Output
標準輸出。輸出一行一個整數,為連接方案數對1000000007取模的結果。
Sample Input
3
0 2 3
2 0 4
3 4 0
Sample Output
50
HINT
對於100%的數據,n為正整數,所有的ci,j為非負整數且不超過1000000007。保證ci,j=cj,i。每組數據的n值如下表所示。
編號 1 2 3 4 5 6 7 8 9 10
n 8 9 9 10 11 12 13 14 15 16
Source
2012國家集訓隊Round 1 day1
感覺還是有點不懂,這個dp來的莫名其妙
g[s]表示狀態為s的點之間任意連邊方案數
f[s]表示s點集構成連通塊方案數
g[]很容易求
現在考慮f[s]應該怎麽求
枚舉s子集 把s劃分成2個部分s1,s2,f[s]+=f[s1]*g[s2]
為什麽這麽轉移可以得到答案呢?
因為這樣可以保證s1和s2之間相互沒有連邊且可以枚舉完所有子集情況又不會重復感性理解。。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define mod 1000000007 #define N 20 #define M 101000 using namespace std; int n,S,a[N][N];long long f[M],g[M]; int main() { int i,j,k,now; scanf("%d",&n); for(i=0;i<n;i++) for(j=0;j<n;j++) scanf("%d",&a[i][j]); S=1<<n; for(i=1;i<S;i++) { g[i]=1; for(j=0;j<n;j++)if(i&(1<<j)) for(k=j+1;k<n;k++)if(i&(1<<k)) g[i]=g[i]*(a[j][k]+1)%mod; f[i]=g[i]; for(j=n-1;j+1;j--) if(i&(1<<j)){now=j;break;} now=i^(1<<now); for(j=now;j;j=(j-1)&now) f[i]=(f[i]-g[j]*f[i^j]%mod+mod)%mod; } cout<<f[S-1]; }
bzoj2560串珠子 狀壓dp+容斥(?)