• [HDU5713]K个联通块


    [HDU5713]K个联通块

    题目大意:

    有一张(n(nle14))个点,(m)条边无重边的无向图,求有多少个边集,使得删掉边集里的边后,图里恰好有(k)个连通块。

    思路:

    一个显然的动态规划是,(f_{s,i})表示点集为(s),分成(i)个连通块的方案数。

    转移什么的都很显然,关键是如何求(f_{s,1})。(万事开头难!)

    (f_{s,1})的含义是删去(s)中若干条边使得新图仍然连通的方案数。我们可以将其转化为任意删边的方案数-删边使得该图不连通的方案数。

    而后者就相对好求。

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<numeric>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    typedef long long int64;
    const int N=14,M=105,mod=1e9+9;
    struct Edge {
    	int u,v;
    };
    Edge e[M];
    int f[1<<N][N+1],cnt[1<<N];
    inline int power(int a,int k) {
    	int ret=1;
    	for(;k;k>>=1) {
    		if(k&1) ret=(int64)ret*a%mod;
    		a=(int64)a*a%mod;
    	}
    	return ret;
    }
    inline int inv(const int &x) {
    	return power(x,mod-2);
    }
    inline int lowbit(const int &x) {
    	return x&-x;
    }
    int main() {
    	const int T=getint();
    	for(register int i=1;i<=T;i++) {
    		memset(f,0,sizeof f);
    		memset(cnt,0,sizeof cnt);
    		const int n=getint(),m=getint(),k=getint();
    		int tmp=0;
    		for(register int i=0;i<m;i++) {
    			e[i]=(Edge){getint()-1,getint()-1};
    			if(e[i].u==e[i].v) tmp++;
    		}
    		for(register int i=0;i<n;i++) f[1<<i][1]=1;
    		for(register int s=0;s<1<<n;s++) {
    			if(__builtin_popcount(s)<=1) continue;
    			for(register int i=0;i<n;i++) {
    				if((s>>i)&1) {
    					for(register int j=0;j<m;j++) {
    						const int &u=e[j].u,&v=e[j].v;
    						if(u==v) continue;
    						if(i==u&&((s>>v)&1)) cnt[s]++;
    						if(i==v&&((s>>u)&1)) cnt[s]++;
    					}
    				}
    			}
    			cnt[s]>>=1;
    			const int v=s^lowbit(s);
    			for(register int t=(v-1)&v;;t=(t-1)&v) {
    				(f[s][1]+=(int64)f[t^lowbit(s)][1]*power(2,cnt[s^t^lowbit(s)])%mod)%=mod;
    				if(!t) break;
    			}
    			f[s][1]=(power(2,cnt[s])-f[s][1]+mod)%mod;
    		}
    		for(register int j=2;j<=k;j++) {
    			for(register int s=1;s<1<<n;s++) {
    				for(register int t=(s-1)&s;t;t=(t-1)&s) {
    					(f[s][j]+=(int64)f[t][j-1]*f[s^t][1]%mod)%=mod;
    				}
    				f[s][j]=(int64)f[s][j]*inv(j)%mod;
    			}
    		}
    		printf("Case #%d:
    %lld
    ",i,(int64)f[(1<<n)-1][k]*power(2,tmp)%mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    MySQL设计之三范式的理解
    git基本操作命令和安装
    MySQL 中<=>用法(长知识)
    举个栗子看如何做MySQL 内核深度优化
    我们来说一说TCP神奇的40ms
    一览js模块化:从CommonJS到ES6
    Vtiger CRM 几处SQL注入漏洞分析,测试工程师可借鉴
    做优化的数据库工程师请参考!CynosDB的计算层设计优化揭秘
    1个开发如何撑起一个过亿用户的小程序
    教你一个vue小技巧,一般人我不说的
  • 原文地址:https://www.cnblogs.com/skylee03/p/9657188.html
Copyright © 2020-2023  润新知