HDU 5713 K个联通块【状压计数dp……补集转化?
2016-12-16 00:02
381 查看
显然可以f[s][i] 表示点集s有i个连通块的方案数,枚举子集的时候,令其中一个的i=1,并强行把lowbit(s)表示的节点塞在i=1的子集里面,就避免了算重
然后考虑如何计算对于点集s 全部连通的方案数,发现好麻烦2333
转化一下 用选边的所有方案数 - 不连通的方案数
不连通的方案数……继续枚举子集,其中一个连通另一部分任选,并把lowbit(s)表示的节点放在联通的那个块里面
反正看代码就好……
明天磕主旋律,听说特别瘠薄233333
#include<bits/stdc++.h>
#define MAXN 16
#define MAXM 110
#define MOD 1000000009
using namespace std; int T,n,m,k;
int lim;
int G[MAXN][MAXN];
int cf[MAXM]; //2的次幂
int f[1<<MAXN][MAXN]; //f[s][i] 点集s有i个连通块的方案数
int num[1<<MAXN]; //点集s的边数
int g[1<<MAXN]; //点集s不连通的方案数
inline void init(){
memset(f,0,sizeof f);
memset(num,0,sizeof num);
memset(G,0,sizeof G);
memset(g,0,sizeof g);
}
inline int count_edge(int s,int pos){
for(int i=0;i<n;++i) if(pos==(1<<i)){
pos = i;break;
}
int rtn = 0;
for(int i=0;i<n;++i){
if((1<<i)&s)
rtn += G[pos][i];
}
return rtn;
}
int main(){
// freopen("1.in","r",stdin);
cf[0] = 1;
for(int i=1;i<MAXM;++i) cf[i] = ((0ll+cf[i-1])<<1)%MOD;
scanf("%d",&T);
int rondd = 0;
while(T--){
init();
scanf("%d%d%d",&n,&m,&k);
lim = (1<<n)-1;
for(int i=1;i<=m;++i){
int x,y;
scanf("%d%d",&x,&y);
--x,--y;
G[x][y] = G[y][x] = 1;
}
for(int i=1;i<=lim;++i){
int tmp = i&-i;
num[i] = num[i^tmp] + count_edge(i,tmp);
}
for(int i=0;i<n;++i) f[1<<i][1] = cf[num[1<<i]];
for(int i=1;i<=lim;++i){
int tmp = i&-i;
for(int j = i^tmp;j;j = (j-1)&(i^tmp))
(g[i] += 1ll* f[j^i][1] * cf[num[j]] % MOD) %= MOD;
f[i][1] = (cf[num[i]] - g[i]+MOD)%MOD;
}
for(int i=1;i<=lim;++i){
int tmp = i&-i;
for(int j = i^tmp;j;j = (j-1)&(i^tmp)){
for(int o = 2;o<=k;++o)
(f[i][o] += 1ll*f[j][o-1] * f[i^j][1]%MOD)%= MOD;
}
}
printf("Case #%d:\n%d\n",++rondd,f[lim][k]);
}
return 0;
}
然后考虑如何计算对于点集s 全部连通的方案数,发现好麻烦2333
转化一下 用选边的所有方案数 - 不连通的方案数
不连通的方案数……继续枚举子集,其中一个连通另一部分任选,并把lowbit(s)表示的节点放在联通的那个块里面
反正看代码就好……
明天磕主旋律,听说特别瘠薄233333
#include<bits/stdc++.h>
#define MAXN 16
#define MAXM 110
#define MOD 1000000009
using namespace std; int T,n,m,k;
int lim;
int G[MAXN][MAXN];
int cf[MAXM]; //2的次幂
int f[1<<MAXN][MAXN]; //f[s][i] 点集s有i个连通块的方案数
int num[1<<MAXN]; //点集s的边数
int g[1<<MAXN]; //点集s不连通的方案数
inline void init(){
memset(f,0,sizeof f);
memset(num,0,sizeof num);
memset(G,0,sizeof G);
memset(g,0,sizeof g);
}
inline int count_edge(int s,int pos){
for(int i=0;i<n;++i) if(pos==(1<<i)){
pos = i;break;
}
int rtn = 0;
for(int i=0;i<n;++i){
if((1<<i)&s)
rtn += G[pos][i];
}
return rtn;
}
int main(){
// freopen("1.in","r",stdin);
cf[0] = 1;
for(int i=1;i<MAXM;++i) cf[i] = ((0ll+cf[i-1])<<1)%MOD;
scanf("%d",&T);
int rondd = 0;
while(T--){
init();
scanf("%d%d%d",&n,&m,&k);
lim = (1<<n)-1;
for(int i=1;i<=m;++i){
int x,y;
scanf("%d%d",&x,&y);
--x,--y;
G[x][y] = G[y][x] = 1;
}
for(int i=1;i<=lim;++i){
int tmp = i&-i;
num[i] = num[i^tmp] + count_edge(i,tmp);
}
for(int i=0;i<n;++i) f[1<<i][1] = cf[num[1<<i]];
for(int i=1;i<=lim;++i){
int tmp = i&-i;
for(int j = i^tmp;j;j = (j-1)&(i^tmp))
(g[i] += 1ll* f[j^i][1] * cf[num[j]] % MOD) %= MOD;
f[i][1] = (cf[num[i]] - g[i]+MOD)%MOD;
}
for(int i=1;i<=lim;++i){
int tmp = i&-i;
for(int j = i^tmp;j;j = (j-1)&(i^tmp)){
for(int o = 2;o<=k;++o)
(f[i][o] += 1ll*f[j][o-1] * f[i^j][1]%MOD)%= MOD;
}
}
printf("Case #%d:\n%d\n",++rondd,f[lim][k]);
}
return 0;
}
相关文章推荐
- myeclipse tomcat的启动缓慢问题----一次会加载多个项目
- 内存介绍 - 继承
- java--Struts2入门示例教程(五)
- Java中Date插入数据库的一些问题总结(二)
- Java中数组的问题(三)
- 浏览器--如何让登陆页面的表单不默认显示账号和密码
- JS切换卡效果
- java项目HTTP Status 404(The requested resource is not avail)的问题
- Java 关于Ajax的实例--验证用户名(四)
- (四)基于myeclipse的RocketMQ--Demo实践
- Java中类与方法的学习笔记(一):
- 由数组随机化排序引出的对于js中sort()方法的理解分析
- JavaEE--prepareStatement后面的setString()方法是为何?
- javaEE--request.getRequestDispatcher--URL后带参数实现自定义跳转
- (五)基于RocketMQ--Demo项目的测试和原理说明
- (三)RocketMQ集群部署实践
- tomcat端口号的配置
- Spring boot 设置登录页面,以及放开需要的页面或文件夹
- Nginx 文档阅读记录
- Nginx 配置示例