题目分析:

听说这题考场上能被$ O(4^n) $的暴力水过,难不成出题人是毕姥爷?

首先思考一个显而易见的$ O(n^2*2^n) $的暴力DP。一般的DP都是考虑最近的加入了哪个点,然后删除后递归进行状压DP。由于这道题的题目询问方式是反过来的,处理方式也反过来。

令$ f[n][S] $表示当前有$ S $这些点,期望这些点能够构成独立集大小为$ n $。正向的考虑选择了哪个点,并把与这个点有连边的所有点在集合内进行删除,令找到的新状态为$ f[n-1][P] $。我们把$ P $中的结点与$ S $中不在$ P $中的点进行标号拼接。写成语言就是$ f[n][S]+=f[n-1][P] * \binom{|S|-1}{|P|} * |P|! $ 由于对于$ S $的每一个点都需要转移一遍,时间复杂度就变成了$ O(n^2*2^n) $。虽然跑得不快,但是由于冗余状态较多,考场上一定比例的人使用这个算法通过了这个题。

现在来考虑把它优化到$ O(n*2^n) $。由于题目期望着你获得一个最大独立集,所以我们可以发现第一维是没有必要的。因为对于一个目标状态$ S $,我们如果知道$ S $对应的最大独立集的大小的话,那么我们必定是奔着这个大小而去的。现在我们用$ g[S] $来表示$ S $对应的最大独立集大小,那么这是一个普及组题目,枚举选点然后求max就行了。再对于$ f[S] $,求$ S $对应的最大独立集大小。首先记录$ g[S] $,然后找删除某个点后的集合变为了$ g[S]-1 $的就是我们想要的转移方案,同样采用带标号的拼接。因为我们没有了第一维的负担,所以时间复杂度骤降为了$ O(n*2^n) $.

ps:我终于会用letax数学公式啦。

代码:

 #include<bits/stdc++.h>
using namespace std; const int maxn = ;
const int mod = ; int n,m;
int connect[maxn];
int f[(<<)+],g[(<<)+],sz[(<<)+];
int arr[(<<)+],C[maxn][maxn],fac[]; int fast_pow(int now,int pw){
if(pw == ) return now;
int z = fast_pow(now,pw/);
z = (1ll*z*z) % mod;
if(pw & ) z = (1ll*z*now)%mod;
return z;
} void read(){
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int u,v; scanf("%d%d",&u,&v);
connect[u] |= (<<v-);
connect[v] |= (<<u-);
}
for(int i=;i<=n;i++) connect[i] |= (<<i-);
} void init(){
C[][] = ;
for(int i=;i<=n;i++){
C[i][] = C[i][i] = ;
for(int j=;j<i;j++) C[i][j] = (C[i-][j-]+C[i-][j])%mod;
}
for(int i=;i<(<<n);i++){
for(int j=;j<n;j++) if((<<j)&i) sz[i]++;
}
fac[] = ;
for(int i=;i<=n;i++) fac[i] = (1ll*fac[i-]*i)%mod;
} void dfs(int now){
arr[now] = ;
for(int i=;i<=n;i++){
if(!((<<i-)&now)) continue;
int p = now - (now&connect[i]);
if(!arr[p]) dfs(p);
g[now] = max(g[now],g[p]+);
}
} void dfs2(int now){
arr[now] = ;
for(int i=;i<=n;i++){
if(!((<<i-)&now)) continue;
int kk = (now&connect[i]),p = now - kk;
if(g[p] != g[now]-) continue;
if(!arr[p]) dfs2(p);
f[now]+=((1ll*C[sz[now]-][sz[p]]*fac[sz[kk]-])%mod)*f[p]%mod;
f[now] %= mod;
}
} void work(){
init();
g[] = ; arr[] = ;
for(int i=;i<(<<n);i++) if(!arr[i]) dfs(i);
memset(arr,,sizeof(arr));
f[] = ; arr[] = ;
dfs2((<<n)-);
int ans = f[(<<n)-];
ans = (1ll*fast_pow(fac[n],mod-)*ans)%mod;
printf("%d",ans);
} int main(){
read();
work();
return ;
}

LOJ2540 [PKUWC2018] 随机算法 【状压DP】的更多相关文章

  1. LOJ2540 PKUWC2018 随机算法 状压DP

    传送门 两种$DP$: ①$f_{i,j}$表示前$i$次选择,最大独立集为$j$时达到最大独立集的方案总数,转移:$a.f_{i,j}+=f_{i+1,j+2^k}$(保证$k$加入后符合条件):$ ...

  2. [LOJ2540] [PKUWC2018] 随机算法

    题目链接 LOJ:https://loj.ac/problem/2540 Solution 写的时候脑子不太清醒码了好长然后时间\(LOJ\)垫底... 反正随便状压\(dp\)一下就好了,设\(f[ ...

  3. 洛谷 P4547 & bzoj 5006 随机二分图 —— 状压DP+期望

    题目:https://www.luogu.org/problemnew/show/P4547 https://www.lydsy.com/JudgeOnline/problem.php?id=5006 ...

  4. loj2540 「PKUWC2018」随机算法 【状压dp】

    题目链接 loj2540 题解 有一个朴素三进制状压\(dp\),考虑当前点三种状态:没考虑过,被选入集合,被排除 就有了\(O(n3^{n})\)的转移 但这样不优,我们考虑优化状态 设\(f[i] ...

  5. 【洛谷5492】[PKUWC2018] 随机算法(状压DP)

    点此看题面 大致题意: 用随机算法求一张图的最大独立集:每次随机一个排列,从前到后枚举排列中的点,如果当前点加入点集中依然是独立集,就将当前点加入点集中,最终得到的点集就是最大独立集.求这个随机算法的 ...

  6. 「算法笔记」状压 DP

    一.关于状压 dp 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...

  7. 算法笔记-状压dp

    状压dp 就是把状态压缩的dp 这样还是一种暴力但相对于纯暴力还是优雅的多. 实际上dp就是经过优化的暴力罢了 首先要了解位运算 给个链接吧 [https://blog.csdn.net/u01337 ...

  8. Luogu4547 THUWC2017 随机二分图 概率、状压DP

    传送门 考虑如果只有$0$组边要怎么做.因为$N \leq 15$,考虑状压$DP$.设$f_i$表示当前的匹配情况为$i$时的概率($i$中$2^0$到$2^{N-1}$表示左半边的匹配情况,$2^ ...

  9. 算法复习——状压dp

    状压dp的核心在于,当我们不能通过表现单一的对象的状态来达到dp的最优子结构和无后效性原则时,我们可能保存多个元素的有关信息··这时候利用2进制的01来表示每个元素相关状态并将其压缩成2进制数就可以达 ...

随机推荐

  1. Kafka笔记--常用指令(新建、删除topic)

    新建topic ./kafka-topics.sh --zookeeper 192.168.1.160:2181 --create --topic kafkatestsmall2 --partitio ...

  2. [转]zookeeper-端口说明

    一.zookeeper有三个端口(可以修改) 1.2181 2.3888 3.2888 二.3个端口的作用 1.2181:对cline端提供服务 2.3888:选举leader使用 3.2888:集群 ...

  3. Sql 截取字段中的字符串

    取 a 字段里有字符x后面的数 right(a, charindex('x',reverse(a))-1))      reverse(字段) 这个函数是把字段倒过来并转换成nvarchar类型 取 ...

  4. Visual Studio2017 Remote Debugger

    前言 大家在使用vs打包后的文件部署到服务器后,有时候我们需要对线网的后台进行调试.但是它不像在VS中.这个时候我们该怎么调试呢? 微软想到了这一点,他们在 VS 中给我们提供了一个功能: Remot ...

  5. LDAP-openldap服务部署和测试(YUM安装)

    1. 概述2. 服务端部署过程2.1 软件包说明2.2 部署过程2.3 配置过程3. 测试4. 生成LDIF格式文件4.1 安装migrationtools工具4.2 用migrationtools生 ...

  6. tomcat多实例方案启动脚本

    批量启动 #!/bin/sh BASE_PATH="/usr/local/tomcat8/tomcat-ins/"bash $BASE_PATH/web1/tomcat.sh st ...

  7. markdown操作手册

    **1.标题** # h1 h1自带分割线 ## h2 ### h3 #### h4 ##### h5 ###### h6 **2.圆点** - 圆点 **3.分割线,-和*都可以** --- *** ...

  8. ecna2017-Game of Throwns

    这题就是给你一个标号为0-n-1的环,然后给你M个操作,操作有两种,一种是直接给一个数,这数的正负代表我当前向前(向后)仍了xx个位置的球,或者给你一个撤销操作表示为 undo m,表示撤销最近的M个 ...

  9. 初学习Qt的一些感悟

    最近用Qt写了个人项目,有如下心得(可能有不准确): Qt尽管没有扩展C++语法,但是有额外编译链,每个Q_OBJECT类编译的时候会用moc工具生成另一个meta C++类,之后就是标准C++编译流 ...

  10. 第十次Scrum meeting

    第十次Scrum  meeting 任务及完成度: 成员 1.2 1.3 陈谋 任务1040:完成stackoverflow的数据处理后的json处理(100%) 任务1114-2:完成对pdf.pp ...