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;
}
原文地址:https://www.cnblogs.com/Iowa-Battleship/p/9501163.html