POJ1737 Connected Graph

一道计数类\(DP\)

原题链接

我们可以用\(n\)个节点能构成的无向图总数减去\(n\)个点能构成的不连通无向图的数量即可得到答案。
因为\(n\)个点之间最多能有\(\dfrac{n\times(n-1)}{2}\)条边,而每次选边构成无向图,对于每一条边只有选与不选两种,所以\(n\)个点能构成的无向图总数为\(2^{\frac{n\times(n-1)}{2}}\)
然后我们计算\(n\)个点能构成的不连通无向图的数量。
我们可以枚举编号为\(1\)的节点所在连通块的大小\(k\),对于每个\(k\),要从剩余\(n-1\)个点中取出\(k-1\)个点来与\(1\)号节点构成一个连通块,共\(C_{n-1}^{k-1}\)种方法,而剩余的\(n-k\)个节点则构成任意无向图,共\(2^{\frac{(n-k)\times(n-k-1)}{2}}\)种。
定义\(f[i]\)表示\(i\)个节点能构成的无向图总数,有状态转移方程:

\(\qquad\qquad f[i]=2^{\frac{i\times(i-1)}{2}}-\sum\limits_{j=1}^{i-1}f[j]\times C_{i-1}^{j-1}\times 2^{\frac{(i-j)\times(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("\n");
}
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\),所以代码会自动补空格,而我本来的风格是没有空格的。

猜你喜欢

转载自www.cnblogs.com/Iowa-Battleship/p/9501163.html