#计数型dp#poj 1737 Connected Graph

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/81989254

PS:THANKS FOR GJR——ssl_xxy

题目

求N个节点的无向连通图(节点有标号)


分析

可以发现,直接求太难求,像上一题Gerald and Giant Chess一样,必须反向求答案,then

f [ i ] = 2 i ( i 1 ) ÷ 2 j = 1 i 1 f [ j ] × C i 1 j 1 × 2 ( i j ) ( i j 1 ) ÷ 2

然后就是高精度了


代码

#include <cstdio>
#include <vector>
#define mod 10000
typedef unsigned long long ull;
std::vector<ull>tri[50]; std::vector<ull>c[50]; std::vector<ull>f[50];
void print(ull ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int min(int a,int b){return (a<b)?a:b;}
int main(){
    for (register int i=0;i<50;i++) c[i].push_back(1);
    for (register int i=0;i<50;i++)
        for (register int j=1;j<=i+1>>1;j++) //只存一半
            c[i].push_back(c[i][j-1]*(i-j+2)/j);//组合公式
    tri[0].push_back(1);
    for (register int i=1;i<50;i++){
        tri[i]=tri[i-1]; ull g=0,s;
        for (register int j=0;j<tri[i].size();j++){//高精乘单精,tri是2^高斯等差数列公式次方
            s=tri[i][j]*(1ll<<i)+g;
            g=s/mod; tri[i][j]=s%mod;
            }
        while (g) tri[i].push_back(g%mod),g/=mod;
    }
    f[0].push_back(1);
    for (register int i=1;i<50;i++){
        f[i]=tri[i];
        for (register int j=0;j<i;j++){
            std::vector<ull>t,t1;  t=tri[i-j-1]; t1.clear(); ull g=0,s;
            for (register int p=0;p<t.size();p++){
                s=t[p]*c[i-1][min(j,i-j)]+g;
                g=s/mod; t[p]=s%mod;
            }
            while (g) t.push_back(g%mod),g/=mod;
            for (register int p1=0;p1<t.size();p1++)
            for (register int p2=0;p2<f[j].size();p2++){//高精乘高精
                if (t1.size()==p1+p2) t1.push_back(t[p1]*f[j][p2]); else t1[p1+p2]+=t[p1]*f[j][p2];
                if (t1.size()==p1+p2+1) t1.push_back(t1[p1+p2]/mod); else t1[p1+p2+1]+=t1[p1+p2]/mod;
                t1[p1+p2]%=mod;
            }
            g=0;
            while (t1.size()<f[i].size()) t1.push_back(0);//一定要注意补0(vector)
            for (register int p=0;p<f[i].size();p++)//高精减高精
            if (f[i][p]>=t1[p]+g) f[i][p]-=t1[p]+g,g=0;
                else f[i][p]+=mod-t1[p]-g,g=1;
        }
    }
    int n;
    while (scanf("%d",&n)==1&&n)
    {
        for (register int j=f[n-1].size()-1;j>=0;j--){
            ull k=mod/10; if (j<f[n-1].size()-1)
            while (k>f[n-1][j]&&k>1) putchar('0'),k/=10;
            print(f[n-1][j]);
        }
        putchar('\n');
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/81989254
今日推荐