zoukankan      html  css  js  c++  java
  • BZOJ 2560: 串珠子 (状压DP+枚举子集补集+容斥)

    (Noip提高组及以下),有意者请联系Lydsy2012@163.com,仅限教师及家长用户。
    2560: 串珠子
    Time Limit: 10 Sec Memory Limit: 128 MB
    Submit: 915 Solved: 603
    [Submit][Status][Discuss]
    Description
      铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子。现在铭铭想用绳子把所有的珠子连接成一个整体。
      现在已知所有珠子互不相同,用整数1到n编号。对于第i个珠子和第j个珠子,可以选择不用绳子连接,或者在ci,j根不同颜色的绳子中选择一根将它们连接。如果把珠子看作点,把绳子看作边,将所有珠子连成一个整体即为所有点构成一个连通图。特别地,珠子不能和自己连接。
      铭铭希望知道总共有多少种不同的方案将所有珠子连成一个整体。由于答案可能很大,因此只需输出答案对1000000007取模的结果。
     
    Input
     标准输入。输入第一行包含一个正整数n,表示珠子的个数。接下来n行,每行包含n个非负整数,用空格隔开。这n行中,第i行第j个数为ci,j。

     
    Output
     标准输出。输出一行一个整数,为连接方案数对1000000007取模的结果。

    Sample Input
    3

    0 2 3

    2 0 4

    3 4 0

    Sample Output
    50
    HINT
      对于100%的数据,n为正整数,所有的ci,j为非负整数且不超过1000000007。保证ci,j=cj,i。每组数据的n值如下表所示。

    编号 1 2 3 4 5 6 7 8 9 10

    n 8 9 9 10 11 12 13 14 15 16

    Source
    2012国家集训队Round 1 day1

    题意:

    思路:

    状压DP,
    我们把n个点压成二进制数代表n个点的状态信息。
    我们设两个数组,
    g[s] 代表s状态下的所有情况(s中为1的节点不一定联通情况)
    即s状态下的点两两之间任意连边(可以不连,所以边数应该+1)

    f[s] 代表s状态下的合法情况(即s中为1的节点之间一定联通)方案数。
    容易知道答案就是 f[(2^n)-1]

    通过枚举二进制状态信息,我们可以在(nn2^n)的时间复杂度来求出g数组,
    然后我们通过容斥原理来求f[s]

    我们枚举所有状态s,然后枚举s的所有子集,设子集为i,那么不合法的情况就是
    g[i]*f[s^i] ,我们减去这些情况,就得到f[s] 了。这里的 s^i 是 i关于集合s的补集。

    枚举子集可以看这个神仙的博客http://www.cnblogs.com/jffifa/archive/2012/01/16/2323999.html

    细节见代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define rt return
    #define dll(x) scanf("%I64d",&x)
    #define xll(x) printf("%I64d
    ",x)
    #define sz(a) int(a.size())
    #define all(a) a.begin(), a.end()
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
    ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
    inline void getInt(int* p);
    const int maxn=700010;
    const int inf=0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    
    const ll mod=1000000007ll;
    
    ll g[maxn];
    ll f[maxn];
    ll a[20][20];
    int n;
    int main()
    {
    //    freopen("D:\common_text\code_stream\in.txt","r",stdin);
        //freopen("D:\common_textcode_stream\out.txt","w",stdout);
        gbtb;
        // cout<<(1<<16)<<endl;
        cin>>n;
        rep(i,0,n)
        {
            rep(j,0,n)
            {
                cin>>a[i][j];
            }
        }
        int maxstate=(1<<n)-1;
        for(int i=1;i<=maxstate;i++)
        {
            g[i]=1ll;
            for(int j=0;j<=n;j++)
                if(i&(1<<j))
                {
                    for(int k=j+1;k<=n;++k)
                        if(i&(1<<k))
                        {
                            g[i]=(g[i]*(a[j][k]+1))%mod;
                        }
                }
            f[i]=g[i];
            int upup = i & (i - 1);
            for (int j = upup; j; j = upup & (j - 1))
            {
                f[i]=(f[i]-g[j]*f[j^i]%mod+mod)%mod;
            }
        }
        cout<<f[maxstate]<<endl;
    
    
    
        return 0;
    }
    
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
    
    
    
    
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    [php-src]一个Php扩展的结构
    告别2015,迎来2016
    [JS]应用splice删除多元素时出现的坑
    [Ng]Angular应用点概览
    [MongoDB]Mongodb攻略
    GNU M4
    [Linux]服务管理:RPM包, 源码包
    [Shell]条件判断与流程控制:if, case, for, while, until
    [Shell]字符截取命令:cut, printf, awk, sed
    [Shell]正则表达式与通配符
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/11152910.html
Copyright © 2011-2022 走看看