题目链接

【SGU 448】Controlled Tournament


题目大意

给定比赛人员个数nnn,你希望赢的人的编号m" role="presentation" style="position: relative;">mmm以及一张n×nn×nn\times n的胜负表,第iii行第j" role="presentation" style="position: relative;">jjj 列为111,代表i" role="presentation" style="position: relative;">iii能赢jjj。
赛制为淘汰赛,求m" role="presentation" style="position: relative;">mmm最后能赢,且总比赛树的最小高度时,一共有多少种可能方案。
n≤16n≤16n\le 16。


题解

看到n≤16n≤16n\le 16,果断使用状态压缩动态规划。
dp[i][height][mask]dp[i][height][mask]dp[i][height][mask]表示已比赛完的人的状态为maskmaskmask,其中第iii个人胜利了,且比赛树的高度为height" role="presentation" style="position: relative;">heightheightheight。
状态转移:枚举子集,当子集submasksubmasksubmask中包含iii,i" role="presentation" style="position: relative;">iii能胜过补集中的jjj的时候,可以转移。
即:dp[i][height][mask]=∑dp[i][height−1][submask]×dp[j][height−1][mask−submask]" role="presentation" style="position: relative;">dp[i][height][mask]=∑dp[i][height−1][submask]×dp[j][height−1][mask−submask]dp[i][height][mask]=∑dp[i][height−1][submask]×dp[j][height−1][mask−submask]dp[i][height][mask]=\sum {dp[i][height-1][submask]\times dp[j][height-1][mask-submask]}。
具体细节见代码。


代码no.1

#include <cstdio>
#include <cstring>
#define mxn 16
#define lgn 4
#define rep(i,l,r) for(int i=(l);i<(r);i++)
typedef long long ll;
int n,m,hi,a[mxn][mxn],cnt[1<<mxn];
int dp[mxn][lgn|1][1<<mxn];
int search(int i,int k,int msk) {if(~dp[i][k][msk]) return dp[i][k][msk];if(msk==1<<i)   return dp[i][k][msk]=1;if(1<<k<cnt[msk])   return dp[i][k][msk]=0;dp[i][k][msk]=0;for(int msk0=msk&(msk-1);msk0;msk0=msk&(msk0-1))if(msk0&(1<<i)) {int msk1=msk^msk0;rep(j,0,n)  if(a[i][j]&&(msk1&(1<<j)))dp[i][k][msk]+=search(i,k-1,msk0)*search(j,k-1,msk1);}return dp[i][k][msk];
}
int main() {memset(dp,-1,sizeof(dp));scanf("%d%d",&n,&m),m--;rep(i,1,1<<n)cnt[i]=cnt[i>>1]+(i&1);rep(i,0,n)  rep(j,0,n)scanf("%1d",a[i]+j);for(;1<<hi<n;hi++);search(m,hi,(1<<n)-1);if(dp[m][hi][(1<<n)-1]==-1)dp[m][hi][(1<<n)-1]=0;printf("%d\n",dp[m][hi][(1<<n)-1]);return 0;
}

代码no.2(加了一些小优化,然并卵)

#include <cstdio>
#include <cstring>
#define mxn 16
#define lgn 4
#define rep(i,l,r) for(int i=(l);i<(r);i++)
typedef long long ll;
int n,m,hi,a[mxn][mxn],cnt[1<<mxn];
int dp[mxn][lgn|1][1<<mxn];
int search(int i,int k,int msk) {if(~dp[i][k][msk]) return dp[i][k][msk];if(msk==1<<i)   return dp[i][k][msk]=1;if(1<<k<cnt[msk])   return dp[i][k][msk]=0;if(!(msk&(1<<i)))   return dp[i][k][msk]=0;dp[i][k][msk]=0;int msk0,msk1,tmsk=msk^(1<<i);for(int tmsk0=tmsk&(tmsk-1);tmsk0;tmsk0=tmsk&(tmsk0-1)) {msk0=tmsk0|(1<<i);msk1=msk^msk0;rep(j,0,n)  if(a[i][j]&&(msk1&(1<<j)))dp[i][k][msk]+=search(i,k-1,msk0)*search(j,k-1,msk1);}msk0=1<<i;msk1=msk^msk0;rep(j,0,n)  if(a[i][j]&&(msk1&(1<<j)))dp[i][k][msk]+=search(i,k-1,msk0)*search(j,k-1,msk1);return dp[i][k][msk];
}
int main() {memset(dp,-1,sizeof(dp));scanf("%d%d",&n,&m),m--;rep(i,1,1<<n)cnt[i]=cnt[i>>1]+(i&1);rep(i,0,n)  rep(j,0,n)scanf("%1d",a[i]+j);for(;1<<hi<n;hi++);search(m,hi,(1<<n)-1);if(dp[m][hi][(1<<n)-1]==-1)dp[m][hi][(1<<n)-1]=0;printf("%d\n",dp[m][hi][(1<<n)-1]);return 0;
}

复杂度分析

状态数量:O(n×logn×2n)O(n×log⁡n×2n)O(n\times \log n\times 2^n)。
众所周知,子集枚举是O(3n)O(3n)O(3^n)的。
所以总复杂度是:O(n×logn×3n)O(n×log⁡n×3n)O(n\times \log n\times 3^n)。
但是为何没有超时呢?
因为有很多状态是没用的。


总结

有没用状态的动态规划往往可以使用记忆化搜索的手段,从而将程序的效率进一步提高。

【SGU 448】Controlled Tournament(状态压缩动态规划)相关推荐

  1. 【动态规划】状态压缩动态规划

    整理的算法模板合集: ACM模板 目录 一.集合类状态压缩动态规划 A. AcWing 91. 最短Hamilton路径 B.AcWing 524. 愤怒的小鸟 二.连通类(棋盘类)状态压缩动态规划 ...

  2. 【转】状态压缩动态规划

    引入  首先来说说"状态压缩动态规划"这个名称,顾名思义,状态压缩动态规划这个算法包括两个特点,第一是"状态压缩",第二是"动态规划". 状 ...

  3. 状态压缩动态规划 - 总结【普及+,提高-】

    状态压缩动态规划是一类特殊的动态规划,通常有一维用来表示一个二进制状态.状态压缩,顾名思义,就是把原来要一个bool数组表示状态压缩到一个int变量里.围绕状压DP,我们将介绍它的前世今生,领略状压D ...

  4. 状态压缩动态规划部分习题详解

    状态压缩动态规划部分习题详解 状压DP部分题目详解 状态压缩动态规划部分习题详解 简介 经典子集类问题 原子弹 最短路与状压DP结合 送礼物 P3959宝藏 旅游 经典网格类 铺地砖 一笔画 其他类型 ...

  5. 铺瓷砖问题 (状态压缩动态规划) (一)

    作者: Phill King 邮箱: phillking1982@163.com 原创文章,转载请注明出处. 题目地址:2411 -- Mondriaan's Dream 问题简单描述: 在一个N行M ...

  6. 状态压缩动态规划 -- 旅行商问题

    旅行商问题: N个点(N<16)的带权有向图D,求一条路径,使得这条路经过每一个点恰好一次. 而且路径上边的权值和最小(或者最大),或者求一条具有这样性质的回路. 状态压缩: 将二进制表示十进制 ...

  7. UOJ 265 NOIP 2016 DAY2 T3 浅谈预处理状态压缩动态规划

    世界真的很大 要是当年我会一点状压该多好.. 虽然现在我状压也很差,但是还是把这道题水出来了 马上要NOIP2017了,抓紧调整状态才好 看题先: description Kiana 最近沉迷于一款神 ...

  8. [NOI2015]寿司晚宴(状态压缩动态规划)

    题目描述 为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴.小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了n−1种不同的寿司,编号1,2,3,⋯,n-1 ...

  9. 0x56. 动态规划 - 状态压缩DP(习题详解 × 7)

    目录 Problem A. 最短Hamilton路径 ProblemB. 蒙德里安的梦想 Problem C. Corn Fields Problem D. 小国王 Problem E. 炮兵阵地 P ...

最新文章

  1. Nagios的安装和基本配置(二:Nagios-Server的安装)
  2. 后台返回不带http的图片路径前台怎么拼接_Shortcuts 教程:一键搞定公众号图片排版...
  3. 模拟游客一天的生活与旅游java程序代写源码
  4. Android牟利之道(一)--界面嵌入有米广告
  5. IOS上 关于状态栏的相关设置(UIStatusBar)和preferredStatusBarStyle不执行问题
  6. 为你总结了N个真实线上故障,从容应对面试官!
  7. 专题开发十二:JEECG微云快速开发平台-基础用户权限
  8. BZOJ 1076: [SCOI2008]奖励关 [DP 期望 状压]
  9. Android 8.0 学习(23)---recovery 流程分析
  10. http android下载工具,安卓抓包工具httpcanary
  11. 实例集群状态为Fail导致的集群混乱排查和复现
  12. 学生免费获取PyCharm专业版
  13. 如何在CentOS系统服务器下搭建代理IP
  14. 基于jQuery/express/socket.io实现的匿名聊天室
  15. 操作系统常见面试总结
  16. vivo x60pro刷机鸿蒙,vivoX60Pro+玩机技巧-有哪些黑科技
  17. 学习记录——微信小程序查询的两种方法
  18. 无法打开内核设备“\.\VMCIDev\VMX”: 操作成功完成。是否在安装 VMware Workstation 后重新引导? 模块“DevicePowerOn”启动失败。 未能启动虚拟机。
  19. MFC注册表CRegKey
  20. oracle form 6i菜单模块,利用DDE技术实现ORACLE FORMS 6i 中打开文件(如:EXCEL、WORD、图片、网页)的功能...

热门文章

  1. Python 中最简最好的设计模式
  2. 【STM32F4系列】【HAL库】旋转编码器(EC11)
  3. HTML常用实体符号
  4. TC3XX 多核ECU的中断向量表解疑
  5. python绘制一份完美的中国地图
  6. 作为维基百科全书的系统、全球最著名的wiki程序——MediaWiki
  7. Git 报错:fatal: destination path ‘.‘ already exists and is not an empty directory.
  8. ip iq 谐波检测matlab仿真,谐波检测技术在配电项目中的应用
  9. 联发科技嵌入式_【MTK联发科技工资】嵌入式软件工程师待遇-看准网
  10. 计算机检索中各符号表示含义,文献检索中符号的含义这些符号在文献检索中的含义:AND、 OR、 NOT、 (W)、 TI、 W/s、 AU、 LENG...