• POJ1737 Connected Graph


    题目链接:POJ1737 Connected Graph
    题目大意:

    求有 (n) 个不同节点的无向连通图的个数
    (nleq 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<<"
    ";
        }
        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;
    }
    
  • 相关阅读:
    Android开发 设置控件边角半圆
    Android开发 使用XML文件设置背景变化
    Android开发 ImageButton加载drawable文件问题
    Android开发 网络检测(使用广播监听)
    android studio无法在可视化页面预览布局文件
    jdbc连接oracle数据库
    「数学」- 暑假后文化课能力复健 20210906 ~ 20210912
    「数学」- 暑假后文化课能力复健 20210830 ~ 20210905
    「数学」高等代数学习笔记
    「数学」浅谈极值点偏移问题的处理技巧
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14063052.html
Copyright © 2020-2023  润新知