插头DP基础题的样子。。。输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物。输出哈密顿回路(可以多回路)方案数。。。

看了个ppt,画了下图。。。感觉还是挺有效的。。。

参考http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html

以及推荐cd琦的论文ppthttp://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html

向中学生学习~~

感觉以后可能还会要看这篇日志。所以特意加了较多的注释。。。观客可以看注释=。=推荐画示意图。。。。

复杂度O(n*m*2^(m+1))

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cmath>
  6. #include <string>
  7. #include <vector>
  8. #include <queue>
  9. #include <set>
  10. using namespace std;
  11.  
  12. #define ll long long
  13. #define inf 0x3f3f3f3f
  14. #define eps 1e-8
  15.  
  16. int a[][];
  17. ll dp[][][<<];
  18. int main(){
  19. int t,ca=;
  20. scanf("%d",&t);
  21. while(t--){
  22. int n,m;
  23. scanf("%d%d",&n,&m);
  24. for(int i=;i<=n;++i)for(int j=;j<=m;++j)scanf("%d",&a[i][j]);
  25. memset(dp,,sizeof(dp));
  26. dp[][][]=;
  27. int ma=(<<(m+));
  28. for(int i=;i<=n;++i){
  29. for(int j=;j<=m;++j){
  30. for(int k=;k<ma;++k){
  31. int d=<<(j-),r=<<j;
  32. if(a[i][j]){// 该位置无障碍
  33. if( ( (k&d)&&(k&r) ) || ( (~k&d)&&(~k&r)) )// 右插下插同时有或同时无,必须翻转
  34. dp[i][j][k]=dp[i][j-][k^d^r];
  35. else // 右插下插只有一个,可翻转可不翻转
  36. dp[i][j][k]=dp[i][j-][k]+dp[i][j-][k^d^r];
  37. }
  38. else {// 该位置有障碍
  39. if((k&d)==&&(k&r)==)// 没有右插没有下插,则方案数跟随
  40. dp[i][j][k]=dp[i][j-][k];
  41. }
  42. }
  43. }
  44. if(i+<=)
  45. for(int k=;k<(<<m);++k)// 换行去掉上一行的右插,下一行的开头没有进来的左插,请画图
  46. dp[i+][][k<<]=dp[i][m][k];
  47. }
  48. printf("Case %d: There are %I64d ways to eat the trees.\n",++ca,dp[n][m][]);
  49. }
  50. return ;
  51. }

做了上面那个入门级别的插头DP。。。做了个还是入门级别的。。。。

输入N,M<=12,以及N*M的01矩阵,'*'('.')表示有(无)障碍物。输出哈密顿单回路方案数。。。

这一题需要用到括号匹配,最小表示法(上面那题可以不用,我的代码就是没有用到的)。。。

这一题参考了别人的代码,尝试了2种表示方法,一种是直接存括号对应的连通分量标号,一种是只存括号的类型。。。

我的第一种方法300+ms,第二种100+ms。。。感觉还是有点区别的。。。因为存连通分量标号需要用到3位(连通分量标号最大值为MAXM/2),而括号类型只需要2位

。。

而这题跟上一题的区别,就是,单哈密顿回路的括号匹配,如果左插是'(',下插是')',那只能在最后一个非障碍物的位置连接。。。。

具体看代码吧。。。还是建议画下示意图。。。

还有一点就是,由于用到HASH,所以HASH太大太小都可能会TLE

300+ms的版本(其实就是那个链接里的。。。。):

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cmath>
  6. #include <string>
  7. #include <vector>
  8. #include <queue>
  9. #include <set>
  10. using namespace std;
  11.  
  12. #define ll long long
  13. #define inf 0x3f3f3f3f
  14. #define eps 1e-8
  15.  
  16. #define maxd 15
  17. #define HASH 100007
  18. #define STATE 1000010
  19.  
  20. int n,m;
  21. int maze[maxd][maxd],code[maxd];
  22. int ch[maxd];//最小表示法使用
  23. int ex,ey;//最后一个非障碍格子的坐标
  24. struct HASHMAP{
  25. int head[HASH],nxt[STATE],sz;
  26. ll state[STATE];
  27. ll f[STATE];
  28. void clear(){sz=;memset(head,-,sizeof(head));}
  29. void push(ll st,ll ans){
  30. int h=st%HASH;
  31. for(int i=head[h];i!=-;i=nxt[i])
  32. if(state[i]==st){
  33. f[i]+=ans;
  34. return;
  35. }
  36. state[sz]=st;
  37. f[sz]=ans;
  38. nxt[sz]=head[h];
  39. head[h]=sz++;
  40. }
  41. }hm[];
  42. void decode(int *code,int m,ll st){
  43. for(int i=m;i>=;i--)code[i]=st&,st>>=;
  44. }
  45. ll encode(int *code,int m){//最小表示法
  46. int cnt=;
  47. memset(ch,-,sizeof(ch));
  48. ch[]=;
  49. ll st=;
  50. for(int i=;i<=m;i++){
  51. if(ch[code[i]]==-)ch[code[i]]=cnt++;
  52. code[i]=ch[code[i]];
  53. st<<=;
  54. st|=code[i];
  55. }
  56. return st;
  57. }
  58. void shift(int *code,int m){
  59. for(int i=m;i>;i--)code[i]=code[i-];
  60. code[]=;
  61. }
  62. void dpblank(int i,int j,int cur){
  63. for(int k=;k<hm[cur].sz;k++){
  64. decode(code,m,hm[cur].state[k]);
  65. int left=code[j-],up=code[j];
  66. if(left&&up){
  67. if(left==up){//只能出现在最后一个非障碍格子
  68. if(i==ex&&j==ey){
  69. code[j-]=code[j]=;
  70. if(j==m)shift(code,m);
  71. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  72. }
  73. }
  74. else{//不在同一个连通分量则合并
  75. code[j-]=code[j]=;
  76. for(int t=;t<=m;t++)
  77. if(code[t]==up)code[t]=left;
  78. if(j==m)shift(code,m);
  79. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  80. }
  81. }
  82. else if(left || up){
  83. int t = left + up;
  84. if(maze[i][j+]){
  85. code[j-]=;
  86. code[j]=t;
  87. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  88. }
  89. if(maze[i+][j]){
  90. code[j-]=t;
  91. code[j]=;
  92. if(j==m)shift(code,m);
  93. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  94. }
  95. }
  96. else{//无插头,则构造新的连通块
  97. if(maze[i][j+]&&maze[i+][j]){
  98. code[j-]=code[j]=;
  99. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  100. }
  101. }
  102. }
  103. }
  104. void dpblock(int i,int j,int cur){
  105. for(int k=;k<hm[cur].sz;k++){
  106. decode(code,m,hm[cur].state[k]);
  107. code[j-]=code[j]=;
  108. if(j==m)shift(code,m);
  109. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  110. }
  111. }
  112. char str[maxd];
  113. void init(){
  114. memset(maze,,sizeof(maze));
  115. ex=;
  116. for(int i=;i<=n;i++){
  117. scanf("%s",str+);
  118. for(int j=;j<=m;j++){
  119. if(str[j]=='.'){// 无障碍
  120. ex=i,ey=j;
  121. maze[i][j]=;
  122. }
  123. }
  124. }
  125. }
  126. void solve(){
  127. int cur=;
  128. ll ans=;
  129. hm[].clear();
  130. hm[].push(,);
  131. for(int i=;i<=n;i++)
  132. for(int j=;j<=m;j++){
  133. hm[cur^].clear();
  134. if(maze[i][j])dpblank(i,j,cur);
  135. else dpblock(i,j,cur);
  136. cur^=;
  137. }
  138. for(int i=;i<hm[cur].sz;i++)
  139. ans+=hm[cur].f[i];
  140. printf("%I64d\n",ans);
  141. }
  142. int main(){
  143. while(~scanf("%d%d",&n,&m)){
  144. init();
  145. if(ex==)puts("");// 没有空的格子
  146. else solve();
  147. }
  148. return ;
  149. }

100+ms的版本(改编自那个链接里的。。。。):

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cmath>
  6. #include <string>
  7. #include <vector>
  8. #include <queue>
  9. #include <set>
  10. using namespace std;
  11.  
  12. #define ll long long
  13. #define inf 0x3f3f3f3f
  14. #define eps 1e-8
  15.  
  16. #define maxd 15
  17. #define HASH 100007
  18. #define STATE 1000010
  19.  
  20. int n,m;
  21. int maze[maxd][maxd],code[maxd];
  22. int ch[maxd];//最小表示法使用
  23. int ex,ey;//最后一个非障碍格子的坐标
  24. struct HASHMAP{
  25. int head[HASH],nxt[STATE],sz;
  26. ll state[STATE];
  27. ll f[STATE];
  28. void clear(){sz=;memset(head,-,sizeof(head));}
  29. void push(ll st,ll ans){
  30. int h=st%HASH;
  31. for(int i=head[h];i!=-;i=nxt[i])
  32. if(state[i]==st){
  33. f[i]+=ans;
  34. return;
  35. }
  36. state[sz]=st;
  37. f[sz]=ans;
  38. nxt[sz]=head[h];
  39. head[h]=sz++;
  40. }
  41. }hm[];
  42. void decode(int *code,int m,ll st){
  43. for(int i=;i<=m;++i)code[i]=st&,st>>=;
  44. }
  45. ll encode(int *code,int m){//最小表示法
  46. ll st=;
  47. for(int i=m;i>=;--i)
  48. st=st<<|code[i];
  49. return st;
  50. }
  51. void shift(int *code,int m){
  52. for(int i=m;i>;i--)code[i]=code[i-];
  53. code[]=;
  54. }
  55. void dpblank(int i,int j,int cur){
  56. for(int k=;k<hm[cur].sz;k++){
  57. decode(code,m,hm[cur].state[k]);
  58. int left = code[j-],up = code[j];
  59. if(left&&up){
  60. if(left== && up==){// 只能出现在最后一个非障碍格子
  61. if(i==ex&&j==ey){
  62. code[j-]=code[j]=;
  63. ll tmp = encode(code,m);
  64. if(j==m)tmp<<=;
  65. hm[cur^].push(tmp,hm[cur].f[k]);
  66. }
  67. }
  68. else{//不在同一个连通分量则合并
  69. if(left== && up==){// ...(...(...))... ==> ...(...)...##...
  70. for(int jj=j-,cnt=;jj>=;--jj){
  71. if(code[jj]==)++cnt;
  72. else if(code[jj]==)--cnt;
  73. if(cnt==){code[jj]=-code[jj];break;}
  74. }
  75. code[j-]=code[j]=;
  76. }
  77. else if(left== && up==){// ...((...)...)... ==> ...##...(...)...
  78. for(int jj=j,cnt=;jj<=m;++jj){
  79. if(code[jj]==)++cnt;
  80. else if(code[jj]==)--cnt;
  81. if(cnt==){code[jj]=-code[jj];break;}
  82. }
  83. code[j-]=code[j]=;
  84. }
  85. else if(left== && up==){// ...(...)(...)... ==> ...(...##...)...
  86. code[j-]=code[j]=;
  87. }
  88. if(j==m)shift(code,m);
  89. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  90. }
  91. }
  92. else if(left || up){
  93. int t = left | up;
  94. if(maze[i][j+]){
  95. code[j-]=;
  96. code[j]=t;
  97. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  98. }
  99. if(maze[i+][j]){
  100. code[j-]=t;
  101. code[j]=;
  102. if(j==m)shift(code,m);
  103. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  104. }
  105. }
  106. else{//无插头,则构造新的连通块
  107. if(maze[i][j+]&&maze[i+][j]){
  108. code[j-]=,code[j]=;
  109. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  110. }
  111. }
  112. }
  113. }
  114. void dpblock(int i,int j,int cur){
  115. for(int k=;k<hm[cur].sz;k++){
  116. decode(code,m,hm[cur].state[k]);
  117. code[j-]=code[j]=;
  118. if(j==m)shift(code,m);
  119. hm[cur^].push(encode(code,m),hm[cur].f[k]);
  120. }
  121. }
  122. char str[maxd];
  123. void init(){
  124. memset(maze,,sizeof(maze));
  125. ex=;
  126. for(int i=;i<=n;i++){
  127. scanf("%s",str+);
  128. for(int j=;j<=m;j++){
  129. if(str[j]=='.'){// 无障碍
  130. ex=i,ey=j;
  131. maze[i][j]=;
  132. }
  133. }
  134. }
  135. }
  136. void solve(){
  137. int cur=;
  138. ll ans=;
  139. hm[].clear();
  140. hm[].push(,);
  141. for(int i=;i<=n;i++)
  142. for(int j=;j<=m;j++){
  143. hm[cur^].clear();
  144. if(maze[i][j])dpblank(i,j,cur);
  145. else dpblock(i,j,cur);
  146. cur^=;
  147. }
  148. for(int i=;i<hm[cur].sz;i++)
  149. ans+=hm[cur].f[i];
  150. printf("%I64d\n",ans);
  151. }
  152. int main(){
  153. while(~scanf("%d%d",&n,&m)){
  154. init();
  155. if(ex==)puts("");// 没有空的格子
  156. else solve();
  157. }
  158. return ;
  159. }

HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)的更多相关文章

  1. 【BZOJ1814】Ural 1519 Formula 1 插头DP

    [BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...

  2. bzoj1814 Ural 1519 Formula 1(插头dp模板题)

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 924  Solved: 351[Submit][Sta ...

  3. bzoj 1814 Ural 1519 Formula 1 插头DP

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 942  Solved: 356[Submit][Sta ...

  4. hdu 1693 Eat the Trees——插头DP

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1693 第一道插头 DP ! 直接用二进制数表示状态即可. #include<cstdio> # ...

  5. HDU 1693 Eat the Trees(插头DP)

    题目链接 USACO 第6章,第一题是一个插头DP,无奈啊.从头看起,看了好久的陈丹琦的论文,表示木看懂... 大体知道思路之后,还是无法实现代码.. 此题是插头DP最最简单的一个,在一个n*m的棋盘 ...

  6. HDU - 1693 Eat the Trees(多回路插头DP)

    题目大意:要求你将全部非障碍格子都走一遍,形成回路(能够多回路),问有多少种方法 解题思路: 參考基于连通性状态压缩的动态规划问题 - 陈丹琦 下面为代码 #include<cstdio> ...

  7. HDU 1693 Eat the Trees(插头DP,入门题)

    Problem Description Most of us know that in the game called DotA(Defense of the Ancient), Pudge is a ...

  8. HDU 1693 Eat the Trees (插头DP)

    题意:给一个n*m的矩阵,为1时代表空格子,为0时代表障碍格子,问如果不经过障碍格子,可以画一至多个圆的话,有多少种方案?(n<12,m<12) 思路: 这题不需要用到最小表示法以及括号表 ...

  9. HDU 1693 Eat the Trees ——插头DP

    [题目分析] 吃树. 直接插头DP,算是一道真正的入门题目. 0/1表示有没有插头 [代码] #include <cstdio> #include <cstring> #inc ...

随机推荐

  1. SQl语句学习笔记(二)

    merge into        when matched then...  when not mached then... merge into t_road_pre_parameter a fr ...

  2. html5手机常见问题与工具分享

    mobileTech A useful tools or tips list for mobile web application developing 这个项目收集移动端开发所需要的一些资源与小技巧 ...

  3. [译]Bundling and Minification

    原文:http://www.asp.net/mvc/overview/performance/bundling-and-minification============================ ...

  4. 【R】如何确定最适合数据集的机器学习算法 - 雪晴数据网

          [R]如何确定最适合数据集的机器学习算法 [R]如何确定最适合数据集的机器学习算法 抽查(Spot checking)机器学习算法是指如何找出最适合于给定数据集的算法模型.本文中我将介绍八 ...

  5. 解决Ckeditor编辑器不显示html实体,自动过滤html的问题

    Ckeditor 4.5.4,在编辑的时候,使用源码编辑,当保存内容包含Javascript.Style标签的时候,数据库中有Javascript.Style标签,输入到页面也可以执行,但是我再次编辑 ...

  6. Inno Setup制作应用程序安装包

    我最近写了一个MFC应用程序,想发给其他的小伙伴玩一玩,直接发了个exe文件过去,结果发现小伙伴那边打不开.原来这个exe文件虽然是MFC静态编译的,但是还依赖了其他几个.dll文件,需要把这几个dl ...

  7. js兼容注意事项--仅供参考

    做BS开发就难免会用到javascript,而每个浏览器对javascript的支持有不同.这就需要我们程序员去兼容他们,不然有些浏览器就无法运行我们的代码.就会造来客户的投诉,如果让BoSS知道了, ...

  8. DEV控件GridControl常用属性设置

    1. 如何解决单击记录整行选中的问题 View->OptionsBehavior->EditorShowMode 设置为:Click 2. 如何新增一条记录 (1).gridView.Ad ...

  9. [转载]Eclipse.ini的相关说明

    原文链接:http://www.cnblogs.com/yan5lang/archive/2011/05/24/2055867.html Eclipse的启动由$ECLIPSE_HOME/eclips ...

  10. 符瑞艺 160809228_C语言程序设计实验2 选择结构程序设计

    实验2- 输入3个数,并按由大到小的顺序输出. 实验要求: 编写一个C程序,输入3个数,并按由大到小的顺序输出. 参考: 源码: #include <stdio.h> int main() ...