题目大意:

给定一个图,一部分点'*'作为障碍物,求经过所有非障碍点的汉密尔顿回路有多少条

基础的插头DP题目,对于陈丹琦的论文来说我觉得http://blog.sina.com.cn/s/blog_51cea4040100gmky.html

这个博客写的更容易理解,不过好像这篇博客里的代码有问题,反正是A不了题目的

不过上面的图和思路写的很清楚,可以作为参考

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4.  
  5. using namespace std;
  6. #define ll unsigned long long
  7. const int HASH_SIZE = ;
  8.  
  9. bool mp[][];
  10. char str[][];
  11. int n, m , k , nn , mm;
  12. int tot[] , bit[] , hash[HASH_SIZE] , state[][HASH_SIZE];
  13. ll dp[][HASH_SIZE] , ans;
  14.  
  15. void init()
  16. {
  17. //每一位用4进制保存,那么对于每一个状态来说都是右移2次,所以这里i*2
  18. for(int i= ; i<= ; i++) bit[i] = i<<;
  19. memset(dp , , sizeof(dp));
  20. tot[] = dp[][] = , ans = k = ;
  21. state[][] = ;
  22. }
  23.  
  24. void hash_in(int s , ll sum)//s表示当前状态,sum是指s状态下共有sum种方式形成
  25. {
  26. // print(s);
  27. // cout<<" "<<sum<<endl;
  28. int p = s%HASH_SIZE;
  29. while(hash[p]){
  30. if(state[k][hash[p]] == s){
  31. dp[k][hash[p]] += sum;
  32. return ;
  33. }
  34. p++;
  35. if(p == HASH_SIZE) p=;
  36. }
  37. hash[p] = ++tot[k];
  38. state[k][hash[p]] = s;
  39. dp[k][hash[p]] = sum;
  40. }
  41.  
  42. void work()
  43. {
  44. for(int i= ; i<=n ; i++){
  45. for(int j= ; j<=m ; j++){
  46. k^= ; //滚动数组
  47. tot[k] = ;
  48. memset(hash , , sizeof(hash));
  49. for(int u= ; u<=tot[-k] ; u++){
  50. int s = state[-k][u] , curs;
  51. ll sum = dp[-k][u];
  52. int p = (s>>bit[j-])& , q = (s>>bit[j])&; //3进制 , 用( , # , )来理解
  53. if(!mp[i][j]){
  54. if(p== && q==) hash_in(s , sum);
  55. }
  56. else{
  57. if(p == && q == ){
  58. if(!mp[i+][j] || !mp[i][j+]) continue;
  59. curs = s + (<<bit[j-]) + (<<bit[j]);
  60. hash_in(curs , sum);
  61. }
  62. else if(!p && q){
  63. if(mp[i][j+]) hash_in(s , sum);
  64. if(mp[i+][j]){
  65. curs = s+q*(<<bit[j-])-q*(<<bit[j]);
  66. hash_in(curs , sum);
  67. }
  68. }
  69. else if(p && !q){
  70. if(mp[i+][j]) hash_in(s , sum);
  71. if(mp[i][j+]){
  72. curs = s - p*(<<bit[j-])+p*(<<bit[j]);
  73. hash_in(curs , sum);
  74. }
  75. }
  76. else if(p+q==){ //可理解为p==1 && q==1
  77. int cnt = ;
  78. for(int v=j+ ; v<=m ; v++){
  79. int w = (s>>bit[v])&;
  80. if(w == ) cnt++;
  81. if(w == ) cnt--;
  82. if(!cnt){
  83. curs = s-(<<bit[v]); //将)转化为( ->状态由2->1 , 减少了一个
  84. break;
  85. }
  86. }
  87. curs = curs-(<<bit[j])-(<<bit[j-]);
  88. hash_in(curs , sum);
  89. }
  90. else if(p+q==){//可理解为p==2 && q==2
  91. int cnt = ;
  92. for(int v=j- ; v>= ; v--){
  93. int w = (s>>bit[v])&;
  94. if(w == ) cnt--;
  95. if(w == ) cnt++;
  96. if(!cnt){
  97. curs= s+(<<bit[v]);
  98. break;
  99. }
  100. }
  101. curs = curs-(<<bit[j])-(<<bit[j-]);
  102. hash_in(curs , sum);
  103. }
  104. else if(p== && q==){
  105. if(i==nn && j==mm)
  106. ans+=sum;
  107. }
  108. else if(p== && q==){
  109. curs = s-(<<bit[j-])-(<<bit[j]);
  110. hash_in(curs , sum);
  111. }
  112. }
  113. }
  114. }
  115. for(int j= ; j<=tot[k] ; j++) state[k][j]<<=;
  116. }
  117. printf("%lld\n" , ans);
  118. }
  119.  
  120. int main()
  121. {
  122. // freopen("in.txt" , "r" , stdin);
  123. while(~scanf("%d%d" , &n , &m))
  124. {
  125. memset(mp , , sizeof(mp));
  126. for(int i= ; i<=n ; i++){
  127. scanf("%s" , str[i]+);
  128. for(int j= ; j<=m ; j++){
  129. mp[i][j] = str[i][j]=='.';
  130. // if(mp[i][j]) cout<<i<<" "<<j<<endl;
  131. if(mp[i][j]) nn=i , mm=j;//记录最后一个可执行块
  132. }
  133. }
  134. init();
  135. work();
  136. }
  137. return ;
  138. }

后来写hdu上的题目的时候觉得kuangbin的表达方式还是很清晰的,所以又将源代码修改成了:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <iostream>
  5.  
  6. using namespace std;
  7. #define ll unsigned long long
  8. const int HASH = ;
  9. const int STATE = ;
  10. const int MAXD = ;
  11. int n , m , enx , eny;
  12. int code[MAXD] , mp[MAXD][MAXD];
  13. ll ans = ;
  14.  
  15. struct HASHMAP{
  16. int head[HASH] , next[STATE] , state[STATE] , size;
  17. ll f[STATE];
  18.  
  19. void init(){
  20. size = ;
  21. memset(head , - , sizeof(head));
  22. }
  23.  
  24. void push_in(int st , ll sum){
  25. int h = st%HASH;
  26. for(int i = head[h] ; ~i ; i=next[i]){
  27. if(st == state[i]){
  28. f[i]+=sum;
  29. return ;
  30. }
  31. }
  32. f[size]=sum;
  33. state[size] = st;
  34. next[size] = head[h];
  35. head[h] = size++;
  36. }
  37. }hashmap[];
  38.  
  39. void decode(int *code , int m , int st)
  40. {
  41. for(int i=m ; i>= ; i--){
  42. code[i] = st&;
  43. st>>=;
  44. }
  45. }
  46.  
  47. int encode(int *code , int m)
  48. {
  49. int st=;
  50. for(int i= ; i<=m ; i++){
  51. st<<=;
  52. st |= code[i];
  53. }
  54. return st;
  55. }
  56.  
  57. void init()
  58. {
  59. char str[MAXD][MAXD];
  60. for(int i= ; i<=n ; i++){
  61. scanf("%s" , str[i]+);
  62. for(int j= ; j<=m ; j++){
  63. if(str[i][j] == '.'){
  64. mp[i][j] = ;
  65. enx = i , eny = j;
  66. }else mp[i][j] = ;
  67. }
  68. mp[i][m+]=;
  69. mp[n+][i] = ;
  70. }
  71. }
  72.  
  73. void shift(int *code , int m) //换行,可理解为将最右侧轮廓线换到了下一行的最左侧
  74. {
  75. for(int i=m ; i>= ; i--) code[i] = code[i-];
  76. code[] = ;
  77. }
  78.  
  79. void dpblank(int i , int j , int cur) //处理可执行格子
  80. {
  81. // cout<<"ok: "<<i<<" "<<j<<endl;
  82. int k , left , up;
  83. for(k= ; k<hashmap[cur].size ; k++){
  84. decode(code , m , hashmap[cur].state[k]);
  85. left = code[j-];
  86. up = code[j];
  87. if(!left && !up){
  88. if(!mp[i][j+] || !mp[i+][j]) continue;
  89. code[j-] = , code[j] = ;
  90. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  91. }
  92. else if(!left && up){
  93. if(mp[i][j+]) hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  94. if(mp[i+][j]){
  95. code[j-] = up , code[j] = ;
  96. if(j == m) shift(code , m);
  97. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  98. }
  99. }
  100. else if(left && !up){
  101. if(mp[i+][j]){
  102. if(j == m) shift(code , m);
  103. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  104. }
  105. if(mp[i][j+]){
  106. code[j-] = , code[j] = left;
  107. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  108. }
  109. }
  110. else if(left== && up == ){
  111. int cnt = ;
  112. for(int v=j+ ; v<=m ; v++){
  113. if(code[v]==)cnt++;
  114. if(code[v]==)cnt--;
  115. if(!cnt){
  116. code[v]=;
  117. break;
  118. }
  119. }
  120. code[j-] = code[j] = ;
  121. if(j == m) shift(code , m);
  122. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  123. }
  124. else if(left == && up == ){
  125. int cnt=;
  126. for(int v=j- ; v>= ; v--){
  127. if(code[v]==)cnt++;
  128. if(code[v]==)cnt--;
  129. if(!cnt){
  130. code[v]=;
  131. break;
  132. }
  133. }
  134. code[j-] = code[j] = ;
  135. if(j == m) shift(code , m);
  136. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  137. }
  138. else if(left== && up==){
  139. if(i==enx && j==eny) ans+=hashmap[cur].f[k];
  140. }
  141. else{
  142. code[j-]=code[j]=;
  143. if(j == m) shift(code , m);
  144. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  145. }
  146. }
  147. }
  148.  
  149. void dpblock(int i , int j , int cur)
  150. {
  151. // cout<<"flase: "<<i<<" "<<j<<endl;
  152. int k , left , up;
  153. for(k= ; k<hashmap[cur].size ; k++){
  154. decode(code , m , hashmap[cur].state[k]);
  155. left = code[j-] , up = code[j];
  156. if(!left && !up){
  157. if(j == m) shift(code , m);
  158. hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
  159. }
  160. }
  161. }
  162.  
  163. ll solve()
  164. {
  165. ans = ;
  166. int cur = ;
  167. hashmap[cur].init();
  168. hashmap[cur].push_in( , );
  169. for(int i= ; i<=n ; i++){
  170. for(int j= ; j<=m ; j++){
  171. hashmap[cur^].init();
  172. if(mp[i][j]) dpblank(i , j , cur);
  173. else dpblock(i , j , cur);
  174. cur ^= ;
  175. }
  176. }
  177. return ans;
  178. }
  179.  
  180. int main()
  181. {
  182. // freopen("in.txt" , "r" , stdin);
  183. while(~scanf("%d%d" , &n , &m))
  184. {
  185. init();
  186. printf("%I64d\n" , solve());
  187. }
  188. return ;
  189. }

URAL 1519 基础插头DP的更多相关文章

  1. URAL Formula 1 ——插头DP

    [题目分析] 一直听说这是插头DP入门题目. 难到爆炸. 写了2h,各种大常数,ural垫底. [代码] #include <cstdio> #include <cstring> ...

  2. Ural 1519 Formula 1 (DP)

    题意:给定一个 n * m 的矩阵,问你能花出多少条回路. #pragma comment(linker, "/STACK:1024000000,1024000000") #inc ...

  3. 【BZOJ1814】Ural 1519 Formula 1 (插头dp)

    [BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...

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

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

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

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

  6. HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...

  7. Ural 1519. Formula 1 优美的插头DP

    今天早上学了插头DP的思想和最基础的应用,中午就开始敲了,岐哥说第一次写不要看别人代码,利用自己的理解一点点得写出来,这样才锻炼代码能力!于是下午慢慢地构思轮廓,一点点地敲出主体代码,其实是很磨蹭的, ...

  8. 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 ...

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

    [题目]1519. Formula 1 [题意]给定n*m个方格图,有一些障碍格,求非障碍格的哈密顿回路数量.n,m<=12. [算法]插头DP [题解]<基于连通性状态压缩的动态规划问题 ...

随机推荐

  1. mustache.js渲染带事件的模板

    http://zccst.iteye.com/blog/2183111 最近遇到这样一个问题,预览内容可点击,问题是通过$.Mustache.render("templateId" ...

  2. D3.js 完整的柱形图

    一个完整的柱形图包含三部分:矩形.文字.坐标轴.制作一个实用的柱形图,内容包括:选择集.数据绑定.比例尺.坐标轴等内容. 1. 添加 SVG 画布 //画布大小 var width = 400; va ...

  3. android中textview设置为多行文本时,如何让文字从最顶开始显示

    <span style="white-space:pre"> </span><EditText android:layout_width=" ...

  4. iOS开发 判断扫码是否为有效网址

    - (BOOL)achiveStringWithWeb:(NSString *)infor { NSString *emailRegex = @"[a-zA-z]+://.*"; ...

  5. POJ 1218

    题目描述看着就乐了,死板得只按着题意来写了ps: tequi是escape的方言版.. #include <iostream> using namespace std; int main( ...

  6. Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 创建复杂数据模型

    Creating a complex data model 创建复杂数据模型 8 of 9 people found this helpful The Contoso University sampl ...

  7. Python顺序集合之 tuple

    慕课网<Python 入门>学习笔记 1.tuple特性 tuple是另一种有序的列表,中文翻译为“ 元组 ”.tuple 和 list 非常类似,但是,tuple一旦创建完毕,就不能修改 ...

  8. ubuntu安装SCrapy

    依次安装 sudo apt-get install build-essential; sudo apt-get install python-dev; sudo apt-get install lib ...

  9. 经典排序算法---冒泡排序(Bubble Sort)

    原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换, 这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头开始进行两两比较交换,直到倒数第二位时结束 void Bubble ...

  10. Sudoku Solver [LeetCode]

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...