POJ - 1737 Connected Graph【计数DP】

An undirected graph is a set V of vertices and a set of E∈{V*V} edges.An undirected graph is connected if and only if for every pair (u,v) of vertices,u is reachable from v.
You are to write a program that tries to calculate the number of different connected undirected graph with n vertices.
For example,there are 4 different connected undirected graphs with 3 vertices.
这里写图片描述

Input

The input contains several test cases. Each test case contains an integer n, denoting the number of vertices. You may assume that 1<=n<=50. The last test case is followed by one zero.

Output

For each test case output the answer on a single line.


题目大意

求N个节点的无向连通图有多少个,每个结点视为互有不同,1<=n<=50


题目分析

直接求可行方案不是很方便,所以试着反过来
N个节点的无向连通图总数=N个节点的无向图总数-N个节点的无向非连通图总数

d p [ i ] 表示i个节点的无向连通图总数

i个节点的无向图
由于其边总数至多有 i ( i 1 ) / 2
每条边有存在与不存在两种情况
所以i个节点的无向连通图总数为 2 i ( i 1 ) / 2

i个节点的无向图非连通图
试枚举包含结点1的连通块大小为j
显然这个连通块有 C i 1 j 1 种选法
那么这个连通块可能的情况总数就有 d p [ j ] C i 1 j 1
除该连通块外剩余 i j 个节点,共有 2 ( i j ) ( i j 1 ) / 2 种组合
得i个节点的无向图非连通图总数为 j = 1 i 1 d p [ j ] C i 1 j 1 2 ( i j ) ( i j 1 ) / 2

最后根据上述推导得递推式
d p [ 1 ] = 1
d p [ i ] = 2 i ( i 1 ) / 2 j = 1 i 1 d p [ j ] C i 1 j 1 2 ( i j ) ( i j 1 ) / 2

另外数据很大,要写高精
高精调的气死人+_+


#include<iostream>
#include<map>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

struct bign
{
    int d[2010];
    int len;
    bign(){ memset(d,0,sizeof(d)); len=0;}
};

const int maxn=55;
int n;
bign C[maxn][maxn];
bign dp[maxn];

bign add(bign a,bign b)
{
    bign c;
    int carry=0;
    for(int i=0;i<a.len||i<b.len;i++)
    {
        int num=a.d[i]+b.d[i]+carry;
        c.d[c.len++]=num%10;
        carry=num/10;
    }
    if(carry!=0) c.d[c.len++]=carry;
    return c;
}

bign mul(bign a,bign b)
{
    bign c; int carry=0;
    if((a.len==1&&a.d[0]==0)||(b.len==1&&b.d[0]==0)){ c.len=1; return c;}
    for(int i=0;i<a.len;++i)
    for(int j=0;j<b.len;++j)
    {
        c.d[i+j]+=a.d[i]*b.d[j];
        if(c.d[i+j]!=0) carry=i+j;
    }

    for(int i=0;i<=carry+7;++i)
    {
        c.d[i+1]+=c.d[i]/10;
        c.d[i]%=10;
        if(c.d[i]!=0) c.len=i+1;
    }
    return c;
}

bign qpow(int k)
{
    bign a,c;
    c.len=1; c.d[0]=1;
    a.len=1; a.d[0]=2;

    while(k>0)
    {
        if(k&1) c=mul(c,a);
        a=mul(a,a);
        k>>=1;
    }
    return c;
}

bign sub(bign a,bign b)
{
    bign c;

    for(int i=0;i<a.len||i<b.len;++i)
    {
        if(a.d[i]<b.d[i]){ a.d[i+1]--; a.d[i]+=10;}
        c.d[c.len++]=a.d[i]-b.d[i];
    }
    while(c.len-1>=1&&c.d[c.len-1]==0) c.len--;
    return c;
}

void print(bign c)
{
    for(int i=c.len-1;i>=0;--i)
    printf("%d",c.d[i]);
}

int main()
{
    for(int i=1;i<=50;++i)
    {
        C[i][0].len=1; C[i][0].d[0]=1;
        C[i][i].len=1; C[i][i].d[0]=1;
        for(int j=1;j<i;++j)
        C[i][j]=add(C[i-1][j],C[i-1][j-1]);
    }

    dp[1].len=1; dp[1].d[0]=1;
    for(int i=2;i<=50;++i)
    {
        bign c;
        dp[i]=qpow(i*(i-1)>>1);
        for(int j=1;j<i;++j)
        c=add( c, mul( dp[j], mul( C[i-1][j-1], qpow((i-j)*(i-j-1)>>1) ) ) );
        dp[i]=sub(dp[i],c);
    }

    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        print(dp[n]);printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/81020529
今日推荐