zoukankan      html  css  js  c++  java
  • CF1221G

    CF1221G - Graph And Numbers

    题目大意

    给定一个(n)(m)边的无向图,(nleq 40)

    求给所有点01染色,满足

    至少存在一条边两边的点均为0

    至少存在一条边两边的点一个为0,一个为1

    至少存在一条边两边的点均为1

    的方案数


    分析

    至少存在 问题并不好处理,由于限制有3个,可以通过(2^3)种情况容斥得到

    设三种边类型为0,1,2

    即计算

    1.不存在0

    2.不存在1

    3.不存在2

    4.不存在01

    5.不存在02

    6.不存在12

    7.不存在012

    逐个击破

    2.即计算所有边连接两个点染色相同方案数,统计连通块即可

    4/6即统计所有点两边都是1/0的方案数

    5即统计所有边两端点颜色不同的方案数,即二分图染色数

    7.即m=0

    1,3类似,可以归纳为每条边两端的点至少有一个为1

    似乎有点类似一般图独立集个数的求解

    由于(nleq 40),考虑 ( ext{meet in the middle})

    枚举半边,判断集合内部是否有非法边,然后根据集合之间的非法边以及自己集合内部为0的点

    确定另一个集合必须选择为1的点集

    因此需要一个父集前缀和

    const int N=45;
    
    int n,m;
    int G[N][N];
    ll E[N]; // 这东西居然要开long long
    
    ll Solve0(){
    	static int S[1<<20];
    	ll ans=0;
    	int m=n/2,A=(1<<m)-1;
    	rep(i,0,(1<<m)-1) {
    		ll T=0;
    		rep(j,0,m-1) if(~i&(1<<j)) T|=E[j];
    		S[i]=(~i&T&A)==0;
    	}
        // 父集前缀和
    	for(int i=1;i<=A;i<<=1) for(int l=0;l<=A;l+=i*2) for(int j=l;j<l+i;++j) S[j]+=S[j+i];
    	rep(i,0,(1<<(n-m))-1) {
    		ll T=0;
    		rep(j,0,n-m-1) if(~i&(1<<j)) T|=E[j+m];
    		if((T>>m)&~i) continue;
    		T&=A,ans+=S[T];
    	}
    	return ans;
    }
    
    ll Solve1(){
    	static int vis[N];
    	function<void(int)> dfs=[&](int u) {
    		if(vis[u]) return;
    		vis[u]=1;
    		rep(i,0,n-1) if(G[u][i]) dfs(i);
    	};
    	ll ans=1;
    	rep(i,0,n-1) if(!vis[i]) dfs(i),ans<<=1;
    	return ans;
    }
    
    ll Solve01(){
    	ll ans=1;
    	rep(i,0,n-1) if(!E[i]) ans<<=1;
    	return ans;
    }
    
    ll Solve02(){
    	static int vis[N],fl=1;
    	function <void(int,int)> dfs=[&](int u,int c) {
    		if(vis[u]) {
    			if(vis[u]!=c) fl=0;
    			return;
    		}
    		vis[u]=c;
    		rep(i,0,n-1) if(G[u][i]) dfs(i,3-c);
    	};
    
    	ll ans=1;
    	rep(i,0,n-1) if(!vis[i]) dfs(i,1),ans<<=1;
    	return fl*ans;
    }
    
    
    int main(){
    	n=rd(),m=rd();
    	rep(i,1,m) {
    		int x=rd()-1,y=rd()-1;
    		G[x][y]=G[y][x]=1;
    		E[x]|=1ll<<y,E[y]|=1ll<<x;
    	}
    	ll ans=1ll<<n;
    	ans-=2*Solve0(),ans-=Solve1();
    	ans+=2*Solve01()+Solve02();
    	if(m==0) ans-=1ll<<n;
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    Ubuntu中文乱码问题解决方案
    微软开业网站----精华 http://www.microsoft.com/opensource/directory.aspx
    微软开源项目
    cnblogs开源合集
    微软开源软件---管理员用的软件
    微软开源项目-codeflex项目介绍
    SQLServer 微软团队开源项目 (web 版?)
    流程引擎2-CCFLOW
    流程引擎1-高人
    sql web Admin 源码.net 升级
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14745807.html
Copyright © 2011-2022 走看看