zoukankan      html  css  js  c++  java
  • bzoj 2560: 串珠子【状压dp】

    正难则反,设g[s]为集合s不一定联通的方案数,这个很好求,把边数+1乘起来即可,f[s]为s一定联通的方案数
    f考虑容斥,就是g[s]-Σf[nw]*g[s^nw],nw是s的子集,这样就减掉了不联通的情况
    这个枚举子集的方法还挺巧的……

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=20,mod=1000000007;
    int n,c[N][N],a[N],tot,f[100005],g[100005];
    int main()
    {
    	scanf("%d",&n);
    	for(int i=0;i<n;i++)
    		for(int j=0;j<n;j++)
    			scanf("%d",&c[i][j]);
    	for(int s=1,len=(1<<n);s<len;s++)
    	{
    		tot=0;
    		for(int i=0;i<n;i++)
    			if(s&(1<<i))
    				a[++tot]=i;
    		g[s]=1;
    		for(int i=1;i<=tot;i++)
    			for(int j=i+1;j<=tot;j++)
    				g[s]=1ll*g[s]*(c[a[i]][a[j]]+1)%mod;
    		f[s]=g[s];//cerr<<g[s]<<endl;
    		for(int i=1,le=(1<<tot);i<le;i++)
    		{
    			int nw=0;
    			for(int j=1;j<=tot;j++)
    				if(i&(1<<(j-1)))
    					nw|=(1<<a[j]);
    			f[s]=(f[s]-1ll*f[nw]*g[s^nw]%mod)%mod;
    		}
            int nw=0; 
            for(int i=0;i<n;i++) 
                if(s&(1<<i)) 
    			{ 
    				nw=(s^(1<<i)); 
    				break;
    			}
            f[s]=g[s];
            for(int i=nw;i;i=nw&(i-1))
                f[s]=(f[s]-1ll*g[i]*f[s^i]%mod)%mod;
    	}
    	printf("%d
    ",(f[(1<<n)-1]+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    struct模块
    socketserver模块
    操作系统的基础知识和进程
    day28
    day27
    内心要强大
    《人生》
    下棋+《人生》
    悲哀+鸡眼
    脑壳疼
  • 原文地址:https://www.cnblogs.com/lokiii/p/9762894.html
Copyright © 2011-2022 走看看