POJ1737 Connected Graph ( n点无向连通图计数
Posted Linnyx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1737 Connected Graph ( n点无向连通图计数相关的知识,希望对你有一定的参考价值。
题意说明:求 \\(n\\) 个点的无向连通图个数
据说已经非常典了,但是我太菜了不会组合数学,最近补档时看到这道题,决定记录下来理理思路
POJ1737 Connected Graph
一道计数类(DP)
原题链接
我们可以用(n)个节点能构成的无向图总数减去(n)个点能构成的不连通无向图的数量即可得到答案。
因为(n)个点之间最多能有(dfrac{n imes(n-1)}{2})条边,而每次选边构成无向图,对于每一条边只有选与不选两种,所以(n)个点能构成的无向图总数为(2^{frac{n imes(n-1)}{2}})。
然后我们计算(n)个点能构成的不连通无向图的数量。
我们可以枚举编号为(1)的节点所在连通块的大小(k),对于每个(k),要从剩余(n-1)个点中取出(k-1)个点来与(1)号节点构成一个连通块,共(C_{n-1}^{k-1})种方法,而剩余的(n-k)个节点则构成任意无向图,共(2^{frac{(n-k) imes(n-k-1)}{2}})种。
定义(f[i])表示(i)个节点能构成的无向图总数,有状态转移方程:
(qquadqquad f[i]=2^{frac{i imes(i-1)}{2}}-sumlimits_{j=1}^{i-1}f[j] imes C_{i-1}^{j-1} imes 2^{frac{(i-j) imes(i-j-1)}{2}})
另外,因为数据很大,需要使用高精度,这里我直接套用我以前打的高精模板,所以代码会显得很长。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 85;
//高精模板
struct big {
static const int base = 100000000;
static const int w = 8;
ll s[N], l;
big()
{
memset(s, 0, sizeof(s));
l = -1;
}
big operator = (const big& b)
{
for (int i = 0; i < N; i++)
s[i] = b.s[i];
l = b.l;
return *this;
}
big operator = (ll num)
{
memset(s, 0, sizeof(s));
l = -1;
do
{
s[++l] = num % base;
num /= base;
} while (num > 0);
return *this;
}
big operator = (int num)
{
memset(s, 0, sizeof(s));
l = -1;
do
{
s[++l] = num % base;
num /= base;
} while (num > 0);
return *this;
}
big operator + (const big& b)
{
big c;
ll x = 0, i;
c = x;
c.l = -1;
for (i = 0; i <= l || i <= b.l; i++)
{
x = x + s[i] + b.s[i];
c.s[++c.l] = x % base;
x /= base;
}
if (x)
c.s[++c.l] = x;
while (!c.s[c.l] && c.l > 0)
c.l--;
return c;
}
big operator + (ll b)
{
big c, d;
d = b;
c = *this + d;
return c;
}
big operator + (int b)
{
big c, d;
d = b;
c = *this + d;
return c;
}
big operator += (const big& b)
{
*this = *this + b;
return *this;
}
big operator += (ll b)
{
big c;
c = b;
*this = *this + c;
return *this;
}
big operator += (int b)
{
big c;
c = b;
*this = *this + c;
return *this;
}
big operator - (const big& b)
{
big c, d;
ll x = 0, i;
d = *this;
c = x;
c.l = -1;
for (i = 0; i <= d.l || i <= b.l; i++)
{
if (d.s[i] < b.s[i])
{
d.s[i + 1]--;
d.s[i] += base;
}
c.s[++c.l] = d.s[i] - b.s[i];
}
while (!c.s[c.l] && c.l > 0)
c.l--;
return c;
}
big operator - (ll b)
{
big c, d;
d = b;
c = *this - d;
return c;
}
big operator - (int b)
{
big c, d;
d = b;
c = *this - d;
return c;
}
big operator -= (const big& b)
{
*this = *this - b;
return *this;
}
big operator -= (ll b)
{
big c;
c = b;
*this = *this - c;
return *this;
}
big operator -= (int b)
{
big c;
c = b;
*this = *this - c;
return *this;
}
big operator * (const big& b)
{
big c;
ll x = 0, i, j;
c = x;
c.l = -1;
for (i = 0; i <= l; i++)
{
x = 0;
for (j = 0; j <= b.l; j++)
{
c.s[i + j] = s[i] * b.s[j] + x + c.s[i + j];
x = c.s[i + j] / base;
c.s[i + j] %= base;
}
c.s[i + b.l + 1] = x;
}
c.l = l + b.l + 1;
while (!c.s[c.l] && c.l > 0)
c.l--;
return c;
}
big operator * (ll b)
{
big c, d;
d = b;
c = *this*d;
return c;
}
big operator * (int b)
{
big c, d;
d = b;
c = *this*d;
return c;
}
big operator *= (const big& b)
{
*this = *this*b;
return *this;
}
big operator *= (ll b)
{
big c;
c = b;
*this = *this*c;
return *this;
}
big operator *= (int b)
{
big c;
c = b;
*this = *this*c;
return *this;
}
big operator / (const big& b)
{
big cc, dd, k;
ll x = 0, i, j, le, r, m;
cc = x;
cc.l = l + b.l;
if (b.l < 1)
{
for (i = b.l; i >= 0; i--)
x = x * base + b.s[i];
cc = *this / x;
return cc;
}
for (i = l; i >= 0; i--)
{
dd.l++;
for (j = dd.l; j >= 1; j--)
dd.s[j] = dd.s[j - 1];
dd.s[0] = s[i];
if (dd < b)
continue;
le = 0;
r = 99999999;
while (le < r)
{
m = (le + r) / 2;
k = m;
k *= b;
if (k <= dd)
le = m + 1;
else
r = m;
}
r -= 1;
cc.s[i] = r;
k = r;
k *= b;
dd -= k;
}
while (!cc.s[cc.l] && cc.l > 0)
cc.l--;
return cc;
}
big operator / (ll b)
{
big cc;
ll x = 0, i;
cc.l = -1;
for (i = l; i >= 0; i--)
{
cc.s[i] = (x*base + s[i]) / b;
x = (x*base + s[i]) % b;
}
cc.l = l;
while (!cc.s[cc.l] && cc.l > 0)
cc.l--;
return cc;
}
big operator / (int b)
{
big c;
ll x = b;
c = *this / x;
return c;
}
big operator /=(const big& b)
{
*this = *this / b;
return *this;
}
big operator /= (ll b)
{
big c;
c = b;
*this = *this / c;
return *this;
}
big operator /= (int b)
{
big c;
c = b;
*this = *this / c;
return *this;
}
big operator % (const big& b)
{
big f, e, kk;
ll x = 0, i, j, le, r, m;
if (b.l < 1)
{
for (i = b.l; i >= 0; i--)
x = x * base + b.s[i];
f = *this%x;
return f;
}
f = x;
f.l = l + b.l;
for (i = l; i >= 0; i--)
{
e.l++;
for (j = e.l; j >= 1; j--)
e.s[j] = e.s[j - 1];
e.s[0] = s[i];
if (e < b)
continue;
le = 0;
r = 99999999;
while (le < r)
{
m = (le + r) / 2;
kk = m;
kk *= b;
if (kk <= e)
le = m + 1;
else
r = m;
}
r -= 1;
f.s[i] = r;
kk = r;
kk *= b;
e -= kk;
}
while (!e.s[e.l] && e.l > 0)
e.l--;
return e;
}
big operator % (ll b)
{
big f, e;
ll x = 0, i;
f.l = -1;
for (i = l; i >= 0; i--)
{
f.s[i] = (x*base + s[i]) / b;
x = (x*base + s[i]) % b;
}
e = x;
return e;
}
big operator % (int b)
{
big c;
ll x = b;
c = *this%x;
return c;
}
big operator %= (const big& b)
{
*this = *this%b;
return *this;
}
big operator %= (ll b)
{
big c;
c = b;
*this = *this%c;
return *this;
}
big operator %= (int b)
{
big c;
c = b;
*this = *this%c;
return *this;
}
bool operator < (const big& b)const
{
if (l != b.l)
return l < b.l;
for (ll i = l; i >= 0; i--)
if (s[i] != b.s[i])
return s[i] < b.s[i];
return false;
}
bool operator > (const big& b)const
{
return b < *this;
}
bool operator <= (const big& b)const
{
return !(b < *this);
}
bool operator >= (const big& b)const
{
return !(*this < b);
}
bool operator != (const big& b)const
{
return b < *this || *this < b;
}
bool operator == (const big& b)const
{
return !(b < *this) && !(*this < b);
}
bool operator < (ll b)const
{
big d;
d = b;
return *this < d;
}
bool operator > (ll b)const
{
big d;
d = b;
return d < *this;
}
bool operator <= (ll b)const
{
big d;
d = b;
return !(d < *this);
}
bool operator >= (ll b)const
{
big d;
d = b;
return !(*this < d);
}
bool operator != (ll b)const
{
big d;
d = b;
return d < *this || *this < d;
}
bool operator == (ll b)const
{
big d;
d = b;
return !(d < *this) && !(*this < d);
}
bool operator < (int b)const
{
big d;
d = b;
return *this < d;
}
bool operator > (int b)const
{
big d;
d = b;
return d < *this;
}
bool operator <= (int b)const
{
big d;
d = b;
return !(d < *this);
}
bool operator >= (int b)const
{
big d;
d = b;
return !(*this < d);
}
bool operator != (int b)const
{
big d;
d = b;
return d < *this || *this < d;
}
bool operator == (int b)const
{
big d;
d = b;
return !(d < *this) && !(*this < d);
}
};
//以上为高精模板
big f[N], fac[N], po[1230];
int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c<'0' || c>'9'; c = getchar())
p = (c == '-' || p) ? 1 : 0;
for (; c >= '0'&&c <= '9'; c = getchar())
x = x * 10 + (c - '0');
return p ? -x : x;
}
void pr(int x)
{
int i;
printf("%lld", f[x].s[f[x].l]);
for (i = f[x].l - 1; i >= 0; i--)
printf("%08lld", f[x].s[i]);
printf("
");
}
big C(int x, int y)
{
return fac[y] / fac[x] / fac[y - x];
}
int main()
{
int i, n, j;
fac[0] = f[1] = po[0] = 1;
for (i = 1; i <= 50; i++)
fac[i] = fac[i - 1] * i;
for (i = 1; i <= 1225; i++)
po[i] = po[i - 1] * 2;
for (i = 2; i <= 50; i++)
{
f[i] = po[(i*(i - 1)) >> 1];
for (j = 1; j < i; j++)
f[i] -= f[j] * C(j - 1, i - 1)*po[((i - j)*(i - j - 1)) >> 1];
}
while (1)
{
n = re();
if (!n)
return 0;
pr(n);
}
return 0;
}
ps:因为我用的是(VS),所以代码会自动补空格,而我本来的风格是没有空格的。
以上是关于POJ1737 Connected Graph ( n点无向连通图计数的主要内容,如果未能解决你的问题,请参考以下文章
POJ 1737 Connected Graph 题解(未完成)
POJ1737 Connected Graph ( n点无向连通图计数