zoukankan      html  css  js  c++  java
  • ●BZOJ 2560 串珠子

    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=2560

    题解:

    容斥,状压计数dp
    首先求出一个数组 g[s] 表示集合内的点的连边方案数(两个点间包括不连边和连边)
    即           n
        g[s]=  ∏ (c[i][j]+1)
                i,j∈s
    然后定义一个 f[s] 表示 s的集合构成联通图的方案数
    直接f[s]=g[s]么?显然不是,因为 g[s]里还包含有不联通的情况。
    所以需要减去一些东西。 一下的操作就比较妙了。
    考虑把 s集合里的最小元素 A 固定,使得集合内的所有点都要在 A 的联通图里。
    然后枚举 s 的所有子集 _s,
    若 A不在 _s里,则表明 A所在的联通图 s - _s 与 _s 没有联通,则这是一类非法方案,
    即 f[s]-=f[s-_s]*g[_s]。
    最后答案就是 f[全集]。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define _ %mod
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    const int mod=1000000007;
    int c[25][25],f[(1<<16)+10],g[(1<<16)+10];
    int n;
    int main()
    {
    	scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&c[i][j]);
    	for(int s=1;s<1<<n;s++){
    		g[s]=1;
    		for(int i=0;i<n;i++) if((1<<i)&s)
    			for(int j=i;j<n;j++) if((1<<j)&s)
    				g[s]=1ll*g[s]*(c[i+1][j+1]+1)_;
    	}
    	for(int s=1;s<1<<n;s++){
    		f[s]=g[s];
    		int ii=s&-s;
    		for(int _s=s;_s;_s=(_s-1)&s) if(~_s&ii)
    			f[s]=((f[s]-1ll*f[s-_s]*g[_s]_+mod)_)_;
    	}
    	printf("%d",f[(1<<n)-1]);
    	return 0;
    }
    


     

  • 相关阅读:
    面试技巧
    [CODEVS1116]四色问题
    [CODEVS1216]跳马问题
    [CODEVS1295]N皇后(位运算+搜索)
    [CODEVS1037]取数游戏
    [CODEVS1048]石子归并
    [NOIP2012]同余方程
    C++深入理解虚函数
    Attention Model
    faster-rcnn系列原理介绍及概念讲解
  • 原文地址:https://www.cnblogs.com/zj75211/p/8029401.html
Copyright © 2011-2022 走看看