题意:有一张无重边的无向图, 求有多少个边集,使得删掉边集里的边后,图里恰好有K个连通块。

1≤T≤20
1≤K≤N≤14
0≤M≤N∗(N+1)/2
1≤a,b≤N

思路:From http://blog.csdn.net/di4covery/article/details/51699544

一个简单的结论:删除边集的个数 = 选择边集的个数 , 这样我们就可以把问题转化为选取若干条边使得图里面恰好有K个联通块。

问题可以转化成三个状态压缩DP来完成(这三个DP都不难)

1、num[ mask ] 表示选取mask状态的点两两连边的边数。(这是一个很小的数)

这个数组我们通过状态压缩DP来求

令 u = lowbit (mask)  (即mask状态中编号最小的那个点)

枚举mask中的点v,计算边u,v的个数tmp

num [ mask ] = num [ mask ^u ] + tmp;

2、f [ mask ] 表示选取mask状态的点 ,构成一个联通块 的方案数

同样,利用上一次求出来的num数组,状态压缩DP来求

容斥原理 : 合法方案数 = 总方案数 - 不合法方案数

总方案数 :  2 ^ num( mask ) (每条边选或者不选)

不合法方案数 = tmp:

令 u = lowbit (mask)

枚举mask一个不包含u的子集s,tmp = tmp + f(mask ^ s) * ( 2 ^ num[ s ] );

上面的式子可以理解为枚举一个包含u的联通块,然后剩下的点两两之间的边选或者不选,这些边不会连接之前的联通块

f [ mask ] = 2 ^ num( mask) - tmp;

3、F[ mask ] [ n ]表示选取mask状态的点,构成n个联通块的方案数

实际上 f[ mask ]是 F[mask][1] ,剩下的状态压缩DP相对简单

枚举mask,枚举n

令u = lowbit( mask ),枚举mask一个不包含u的子集s

F[ mask ][ n ] = F[ s ][ n-1 ] * F[ mask ^ s ][ 1 ]

上面的式子等价于F[ mask ][ n ] = F [ s ][ n-1 ] * f[ mask ^ s ]

答案即为F[ mask ] [ n ] (mask为所有点都选择的状态,就是2^n - 1)

Pascal对拍已A,卡常没办法,估计如果去年现场做要跪(现在也跪)

 const mo=;
var g:array[..,..]of int64;
f:array[..]of int64;
two:array[..]of int64;
num:array[..]of longint;
a:array[..,..]of longint;
cas,v,i,t,x,y,sta,max,k1,n,m,j:longint;
tmp:int64; function lowbit(x:longint):longint;
begin
exit(x and (-x));
end; begin
assign(input,'hdoj5713.in'); reset(input);
assign(output,'hdoj5713.out'); rewrite(output);
readln(cas);
two[]:=;
for i:= to do two[i]:=two[i-]* mod mo;
for v:= to cas do
begin
readln(n,m,k1); max:=(<<n)-;
for i:= to n do
for j:= to n do a[i,j]:=;
for i:= to max do
begin
num[i]:=; f[i]:=;
end;
for i:= to max do
for j:= to n do g[i,j]:=;
for i:= to m do
begin
read(x,y);
a[x,y]:=; a[y,x]:=;
end;
for i:= to max do
begin
x:=lowbit(i); y:=round(ln(x)/ln())+;
num[i]:=num[i xor x];
for j:= to n do
if i and (<<(j-))> then num[i]:=(num[i]+a[y,j]) mod mo;
end;
for sta:= to max do
begin
x:=lowbit(sta);
t:=sta xor x; y:=t; tmp:=;
while t> do
begin
tmp:=tmp+f[sta xor t]*two[num[t]];
tmp:=tmp mod mo;
t:=y and (t-);
end;
f[sta]:=(two[num[sta]]-tmp) mod mo;
end;
for i:= to max do g[i,]:=f[i];
for sta:= to max do
for i:= to k1 do
begin
x:=lowbit(sta);
t:=sta xor x; y:=t;
while t> do
begin
g[sta,i]:=g[sta,i]+g[t,i-]*f[sta xor t];
g[sta,i]:=g[sta,i] mod mo;
t:=y and (t-);
end; end; writeln('Case #',v,':');
writeln(g[max,k1]);
end; close(input);
close(output);
end.

对拍用的C++ 1000+MS

 #include <iostream>
#include <cstdio>
#include <cstring>
#define MAXMASK 65537
#define N 20
#define mod 1000000009LL using namespace std; int e[N][N],n,m,k,MASK,num[MAXMASK];
long long F[MAXMASK][N],f[MAXMASK]; inline int lowbit(int x){return x & (-x);}; int edge(int s, int p) {
int ans = ;
for (int i = ; i <= n; i++)
if ((<<(i-)) == p) {p = i;break;}
for (int i = ; i <= n; i++) if ((<<(i-))&s) ans += e[i][p];
return ans;
} int main()
{
freopen("hdoj5713.in","r",stdin);
freopen("right.out","w",stdout);
int T = ;
scanf("%d",&T);
for (int rank=;rank<=T;rank++)
{
memset(e,,sizeof(e));
memset(F,,sizeof(F));
memset(f,,sizeof(f));
memset(num,,sizeof(num));
scanf("%d%d%d",&n,&m,&k);
MASK = ( << n) - ;
for (int i=;i<=m;i++) {
int a,b;
scanf("%d%d",&a,&b);
e[a][b] = e[b][a] = ;//顺带处理自环:)
}
//计算mask状态下的边数
for (int i=;i<=MASK;i++) {
int t = lowbit(i);
num[i] = num[i^t] + edge(i,t);//往状态里新增加一个点
} //状态压缩DP求小f for (int s=;s<=MASK;s++){
int t = lowbit(s);
long long tmp = 0LL;
for (int i=(s^t);i>;i=((i-)&(s^t))) {
tmp += f[s^i] * 1LL*(1LL << num[i]);
tmp %= mod;
}
f[s] = (1LL*(1LL<<num[s]) - tmp) % mod;
}
// for (int s=1;s<=MASK;s++) printf("%d\n",f[s]);
//小f为大F的第一项
for (int s=;s<=MASK;s++) F[s][] = f[s]; //状态压缩DP求大F
for (int s=;s<=MASK;s++)
for (int i=;i<=k;i++) {
int t = lowbit(s);
for (int j=s^t;j>;j=(j-)&(s^t)) {//枚举s的子集
F[s][i] += F[j][i-] * f[s^j];
F[s][i] %= mod;
}
} //防止答案小于0
while (F[MASK][k] < ) F[MASK][k] += mod;
printf("Case #%d:\n%I64d\n", rank, F[MASK][k]);
}
return ;
}

【HDOJ5713】K个联通块(状压DP,计数)的更多相关文章

  1. tyvj2054 四叶草魔杖——连通块 & 状压DP

    题目:http://www.joyoi.cn/problem/tyvj-2054 把点分成几个连通块,和为0的几个点放在一块,在块内跑最小生成树作为这个块的代价: 然后状压DP,组成全集的最小代价就是 ...

  2. 【BZOJ1688】[Usaco2005 Open]Disease Manangement 疾病管理 状压DP

    [BZOJ1688][Usaco2005 Open]Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) ...

  3. [luoguP1896] [SCOI2005]互不侵犯King(状压DP)

    传送门 先预处理出来一行中放置国王的所有情况和每种情况所用的国王个数. f[i][j][k]表示前i行放j个国王且最后一行的状态为k的方案数 状压DP即可 #include <cstdio> ...

  4. Codeforces Gym 100610 Problem K. Kitchen Robot 状压DP

    Problem K. Kitchen Robot Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10061 ...

  5. K - Painful Bases 状压dp

    Painful Bases LightOJ - 1021 这个题目一开始看,感觉有点像数位dp,但是因为是最多有16进制,因为限制了每一个数字都不同最多就有16个数. 所以可以用状压dp,看网上题解是 ...

  6. [WC2008]游览计划(状压dp)

    题面太鬼畜不粘了. 题意就是给一张n*m的网格图,每个点有点权,有k个关键点,让你把这k个关键点连成一个联通快的最小代价. 题解 这题nmk都非常小,解法肯定是状压,比较一般的解法插头dp,但不太好写 ...

  7. 状压dp专题复习

    状压dp专题复习 (有些题过于水,我直接跳了) 技巧总结 : 1.矩阵状压上一行的选择情况 \(n * 2^n\) D [BZOJ2734][HNOI2012]集合选数 蒻得不行的我觉得这是一道比较难 ...

  8. 状压DP小拼盘

    有的DP题,某一部分的状态只有两种,选或不选. 开数组记录,代价太大,转移不方便. 状态压缩意为,用 “0/1“ 表示 “选/不选“ . 把状态表示为二进制整数. There are 10 kinds ...

  9. 【BZOJ1725】[Usaco2006 Nov]Corn Fields牧场的安排 状压DP

    [BZOJ1725][Usaco2006 Nov]Corn Fields牧场的安排 Description Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M< ...

随机推荐

  1. [转]WF事件驱动

    本文转自:http://www.cnblogs.com/Mayvar/archive/2011/09/03/wanghonghua_201109030446.html 已经有不少朋友知道Workflo ...

  2. Webform 内置对象(Response对象、Request对象,QueryString)

    Response对象:响应请求 Response.Write("<script>alert('添加成功!')</script>"); Response.Re ...

  3. Aspose.Word 的常见使用(2018-12-26 更新版)

    Aspose.Word 的常见使用 起因 因项目需要,而且使用html转Word的时候,样式不兼容问题,于是只能使用Aspose.Word通过代码生成.下面是通过DocumentBuilder来设计W ...

  4. Thinkphp3.23 连接MSSQL方法

    Thinkphp 3.23要连接MSSQL,必须配置下,以下是主要的步骤. 1.要安装Microsoft Drivers for PHP for SQL Server驱动 下载驱动以前,要查看一下ph ...

  5. 公众号如何获取已关注用户的unionid的问题

    避免误导,先加一句:首先,得公众号绑定开放平台 这个问题困扰了我一早上,我尝试了很多次获取unionid都失败. 微信的开发文档上有说: 关于特殊场景下的静默授权 1.上面已经提到,对于以snsapi ...

  6. Objective -C Object initialization 对象初始化

    Objective -C Object initialization 对象初始化 1.1 Allocating Objects  分配对象 Allocation is the process by w ...

  7. iOS定位--CoreLocation框架

    CoreLocation框架的使用 // 首先导入头文件 #import <CoreLocation/CoreLocation.h> CoreLocation框架中所有数据类型的前缀都是C ...

  8. C/C++ new/delete []、内存泄漏、动态数组

    一.概念 new/delete是用于动态分配和撤销内存的运算符.new/delete是c++里才有的,c中是用malloc和free,c++虽然也可以用,但是不建议用.当我们使用关键字new在堆上动态 ...

  9. Swift protocol extension method is called instead of method implemented in subclass

    Swift protocol extension method is called instead of method implemented in subclass protocol MyProto ...

  10. inux 软件编译、安装、删除

    640?wx_fmt=otherimage.png 本文学习内容 手动安装软件 手动安装下载源码的软件 源码编译3步骤 deb包-包依赖管理 dekg -l 查看所以安装deb的包 apt-get仓库 ...