[HDU5713]K个联通块

[HDU5713]K个联通块

题目大意:

有一张\(n(n\le14)\)个点,\(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:\n%lld\n",i,(int64)f[(1<<n)-1][k]*power(2,tmp)%mod);
	}
	return 0;
}
posted @ 2018-09-16 20:08  skylee03  阅读(185)  评论(0编辑  收藏  举报