【題目連結】http://poj.org/problem?id=1737
【題目大意】給定一個數n(1<=n<=50),求這n個點構成連通圖的方法種數。
【分析】
貼下別人的部分題解:
利用補集轉化思想, 若不考慮連通性,則有n個點的任意圖有G(n)=2^C(n, 2)個. 只要求出不連通圖的個數就知道答案F(n). 考慮含結點1的連通塊C, |C| = k. 由於不連通,有k < n成立. 則有C(n - 1, k – 1)種方法選擇另k-1個結點與結點1組成C. 所以有C(n - 1, k – 1) * F(k)種方法組成C. 剩下的結點組成一個任意圖即可. 答案為:
(以上可以作為結論,以後可能用到)
我們整個代碼過程,就是先求出組合數,然後是g[]數組,最後是f[]數組,求f[]數組過程中公式裡的k是從1到n-1。由於資料量大,整個過程必須用到高精度。
【代碼】
/*1737 Accepted 1420K 32MS C++ 5274B 2011-02-05 21:06:26 */
#include<stdio.h>
#include<string.h>
#include"bigint.h"
int f[52][200],g[52][200],c[52][52][200];
int Tmp[200],tmp[200],sum[200];
void Cal_comb(){//計算群組合數;
int i,j;
copy(c[1][1],ONE),copy(c[1][0],ONE),copy(c[0][0],ONE);
for(i=2;i<50;i++){
copy(c[i][0],ONE), copy(c[i][i],ONE);
for(j=1;j<i;j++)
add(c[i-1][j-1],c[i-1][j],c[i][j]);
}
//PN(c[10][9]);
}
void Init_gn(){
int i,tim;
copy(g[1],ONE),add(ONE,ONE,g[2]),copy(tmp,g[2]);
for(i=3;i<=50;i++){
copy(sum,ONE);
tim=i*(i-1)/2; //冪次;
while(tim--){
copy(Tmp,ZERO);
mult(tmp,sum,Tmp);
copy(sum,Tmp);
}
copy(g[i],sum);
}
}
void Init_fn(){
int i,j;
copy(f[1],ONE), copy(f[2],ONE);
for(i=3;i<=50;i++){
copy(sum,ZERO);
for(j=1;j<i;j++){
mult(f[j],g[i-j],tmp);
mult(tmp,c[i-1][j-1],Tmp);
add(Tmp,sum,tmp);
copy(sum,tmp);
}
sub(g[i],sum,f[i]);
}
}
int main()
{
int n,i,j,k;
Cal_comb();
Init_gn();
Init_fn();
//PN(f[12]); printf("%d/n",f[12][0]); //93
//PN(g[12]); printf("%d/n",g[12][0]);
while(scanf("%d",&n),n)
PN(f[n]);
}