题目分析:

听说这题考场上能被$ 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. C# 16进制与字符串、字节数组之间的转换 (转载)

    1.请问c#中如何将十进制数的字符串转化成十六进制数的字符串 //十进制转二进制 Console.WriteLine(, )); //十进制转八进制 Console.WriteLine(, )); / ...

  2. Scrum与看板区别

    看板:在制品(work-in-progress, WIP)必须被限制 WIP上限和拉动式生产   1. Scrum与看板简述 Scrum:组织拆分,工作拆分,开发时间拆分,优化发布计划,过程优化 看板 ...

  3. beta阶段测试基本概况对应机型硬件信息

    机型测试概况 测试结果 测试终端数 品牌分布分析 系统分布分析 分辨率分布 未执行 1 联想 4.0.3 480*800 安装失败 1 联想 4.2.1 480*854 通过 119 华为, 三星, ...

  4. 个人博客作业Week2 是否需要有代码规范

    问题:是否需要有代码规范 对于是否需要有代码规范,请考虑下列论点并反驳/支持: 1.这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. 2.我是个艺术家,手艺人,我有 ...

  5. 《Linux内核设计与实现》第3章读书整理

    第三章.进程管理 3.1进程 1.进程就是处于执行期的程序,但进程并不仅仅局限于一段可执行程序代码 2.执行线程: 简称线程,是在进程中活动的对象.每个线程都拥有一个独立的程序计数器.进程栈和一组进程 ...

  6. react-native 基础知识的学习

    react已经用了半年多了,年后有时间想探究一下奇妙的react-native,还别说确实刁,具体哪里刁后面会补充,因为搭建教程,以及入门教程没来得及写,这里先来写一些基础知识的心得. 为什么reac ...

  7. 正则表达式(java)

    概念: 正则表达式,又称规则表达式.(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念. 正则表通常被用来检索.替换那些符合某个模式( ...

  8. 【Alpha发布】网站已经正式发布!

    Alpha版本发布说明 一.功能介绍 本团队所做的物理实验网站是以生成物理实验报告为基础功能的网站.Alpha版本具有的功能大体如下: Figure 1首页 1. 注册登录功能 用户可以通过在注册页通 ...

  9. HDU 2087 剪花布条 (字符串哈希)

    http://acm.hdu.edu.cn/showproblem.php?pid=2087 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图 ...

  10. Tomcat7注册为Linux服务

    https://www.openprogrammer.info/2015/06/14/how-to-install-java-8-and-tomcat-8-on-centos-6-as-service ...