poj1737 Connected Graph(组合数学)

题意:

就是给出结点个数,这些结点都认为是不一样的,要你求出这些点能组成多少种无向图的全连通图

f(n)表示n个结点共有多少种方案。

n个结点的总方案数为H[C(n,2)]=2^C(n,2);

然后排除不连通的情况,设与结点1连通的点数为k个,这k个点从n-1个点中选取,而包含1的k+1个结点是个连通图,所以有C(n-1, k) * f(k+1)方案

而剩下的n-k-1个结点各点之间任意连接方案数为2^C(n-k-1, 2),所以总的不连通的方案数为C(n-1, k) * f(k+1) * 2^C(n-k-1, 2)

所以f(n) = 2^C(n,2) -sum( C(n-1, k) * f(k+1) * 2^C(n-k-1, 2));      0 <=k <= n-1

因为数值很大,要用到大整数

这里求C(n,k)用到公式C(n,k) = C(n-1, k) + C(n-1, k-1)

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.

求n个带标号的点组成的连通图的数目。

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.

Sample Input

1
2
3
4
0

Sample Output

1
1
4
38
AC代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#define maxn 405
#define INF 999999999
#define LL long long
using namespace std;
int C[60][60][500];
int f[60][500];
int H[2000][500];
void print(int *a)
{
    int n = a[0];
    printf("%d", a[--n]);
    for (--n; n; n--) printf("%04d", a[n]);
    printf("\n");
}
const int base = 1e4;
void largemul(int *a, int *b, int *ans)
{
    memset(ans, 0, sizeof(int)*(a[0] + b[0]));
    for (int i = 1; i < a[0]; i++)
    {
        for (int j = 1; j < b[0]; j++)
        {
            ans[i + j - 1] += a[i] * b[j];
            ans[i + j] += ans[i + j - 1] / base;
            ans[i + j - 1] %= base;
        }
    }
    int &l = ans[0];
    l = a[0] + b[0] - 2;
    while (l > 1 && !ans[l]) l--;
    l++;
}
void larget(int *a, int x)
{
    a[0] = 2;
    a[1] = x;
}
void largeplus(int *a, int *b, int *ans)
{
    int l = max(a[0], b[0]);
    memset(ans, 0, sizeof(int)*(l + 1));
    for (int i = 1; i < l; i++)
    {
        if (i >= a[0]) a[i] = 0;
        if (i >= b[0]) b[i] = 0;
        ans[i] += a[i] + b[i];
        ans[i + 1] += ans[i] / base;
        ans[i] %= base;
    }
    ans[0] = (ans[l] ? l + 1 : l);
}

void largesub(int *a, int *b, int *ans)
{
    memset(ans, 0, sizeof(int)*(a[0] + 1));
    for (int i = 1; i < a[0]; i++)
    {
        if (i >= b[0]) b[i] = 0;
        ans[i] += a[i] - b[i];
        if (ans[i] < 0)
        {
            ans[i] += base;
            ans[i + 1]--;
        }
    }
    ans[0] = a[0];
    while (ans[0] > 1 && !ans[ans[0] - 1]) ans[0]--;
}
void pre()
{
    larget(H[0], 1);
    for (int i = 1; i <= 1225; i++)
        largeplus(H[i - 1], H[i - 1], H[i]);
    for (int i = 0; i <= 50; i++)
    {
        larget(C[i][0], 1);
        larget(C[i][i], 1);
        for (int j = 1; j < i; j++)
            largeplus(C[i - 1][j], C[i - 1][j-1], C[i][j]);
    }
    
}
void inti()
{
    larget(f[1], 1);
    for (int i = 2; i <= 50; i++)
    {
        int aa1[500], aa2[500], aa3[500];
        int *a1 = aa1, *a2 = aa2, *a3 = aa3;
        larget(a3, 0);
        for (int j = 0; j < i - 1; j++)
        {
            largemul(C[i - 1][j], f[j + 1], a1);
            largemul(a1, H[(i - j - 1)*(i - j - 2) / 2], a2);
            largeplus(a2, a3, a1);
            swap(a1, a3);
        }
        largesub(H[i*(i - 1) / 2], a3, f[i]);
    }
}

int main()
{
    int n;
    pre();
    inti();
    while (scanf("%d", &n) && n)
    {
        print(f[n]);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值