POJ1737 Connected Graph

题目链接:POJ1737 Connected Graph
题目大意:
求有 \(n\) 个不同节点的无向连通图的个数
\(n\leq 50\)

思路:
\(F[i]\) 为大小为 \(i\) 时的答案,考虑将 \(i\) 号点向外连的边删去,此时图分成两个连通块,对于节点 \(1\) ,设其所在的连通块大小为 \(j\) ,选取该连通块剩下节点的方案数为 \(C_{i-2}^{j-1}\) ,再将 \(j\) 和另外一个连通块的边重新连上,这两个图的方案数显然各自为 \(F[j]\)\(F[i-j]\) ,枚举 \(j\)\(i\) 所在的连通块原先有那些边相连,由于图是连通的,所以不能一条边不连,这里的方案数为 \(2^j-1\)
这样,我们得到了递推式:

\[F[i]=\sum_{j=1}^{i-1}{C_{i-2}^{j-1}*F[j]*f[i-j]*(2^j-1)} \]

注意到 \(n\) 的范围为50的时候答案会超long long,所以要写高精,这道题从补集的角度考虑有另外的一个递推式:

\[F[i]=2^{i*(i-1)/2}-\sum_{j=1}^{i-1}{F[j]*C_{i-1}^{j-1}*2^{(i-j)*(i-j-1)/2}} \]

不过这个式子实现时比前者要多写一个减法的高精,同时 \(2^{i*(i-1)/2}\) 也要高精预处理,所以写起来稍微麻烦一点。

Code:

#include<iostream>
#include<cstring>
#define N 51
using namespace std;
struct Big_int{
    int p[600],siz;
    Big_int(){siz=0;}
    void print(){
        for(int i=siz-1;i>=0;i--)cout<<p[i];
        cout<<"\n";
    }
    Big_int operator +(const Big_int b)const{
        Big_int ret;ret.siz=max(siz,b.siz);
        memset(ret.p,0,sizeof(ret.p));
        for(int i=0;i<ret.siz;i++){
            ret.p[i]+=p[i]+b.p[i];
            if(ret.p[i]>=10){
                ret.p[i]-=10,ret.p[i+1]+=1;
                ret.siz=max(ret.siz,i+2);
            }
        }
        return ret;
    }
    Big_int operator *(const Big_int b)const{
        Big_int ret;
        memset(ret.p,0,sizeof(ret.p));
        for(int i=0;i<siz;i++){
            for(int j=0;j<b.siz;j++)
                ret.p[i+j]+=p[i]*b.p[j];
        }
        for(int i=0;i<b.siz+siz;i++){
            if(ret.p[i])ret.siz=max(ret.siz,i+1);
        }
        for(int i=0;i<ret.siz;i++){
            if(ret.p[i]>=10){
                ret.p[i+1]+=ret.p[i]/10,ret.p[i]%=10;
                ret.siz=max(ret.siz,i+2);
            }
        }
        return ret;
    }
    Big_int operator / (const int b)const{
        Big_int ret;
        int left=0;
        for(int i=siz-1;i>=0;i--){
            left=left*10+p[i];
            if(ret.siz==0&&(left/b)==0)continue;
            if(ret.siz==0)ret.siz=i+1;
            ret.p[i]=left/b,left%=b;
        }
        return ret;
    }
}f[N],pow[N],one;
Big_int turn(long long k){
    Big_int ret;
    while(k)ret.p[ret.siz++]=k%10,k/=10;
    return ret;
}
int n;
Big_int C(int n,int m){
    Big_int ret=one;
    for(int i=n,j=1;j<=m;i--,j++)
        ret=(ret*turn(i))/j;
    return ret;
}
void init(){
    one.siz=1,one.p[0]=1;
    f[1]=f[2]=one;
    for(int i=3;i<=50;i++){
        for(int j=1;j<i;j++)
            f[i]=f[i]+C(i-2,j-1)*f[j]*f[i-j]*turn((1ll<<j)-1);
    }
}
int main(){
    init();
    while(cin>>n&&n)f[n].print();
    return 0;
}
posted @ 2020-11-30 19:22  Neal_lee  阅读(128)  评论(0编辑  收藏  举报