当前位置:   article > 正文

dp-插头dp

dp-插头dp

插头dp通常用来解决棋盘上的连通性、回路问题,采用按格递推的方式求解,虽然理论状态较多,但是实际的合法状态较少

令f [ i , j , s ] 表示递推到 i , j 这个格子,状态是 s

插头dp枚举格子时需要 记录 x , y哪条边有边伸出,记录属于哪个连通块,(这样说有点抽象,等会画图就清楚了),记录连通块有两种方法,最小表示法和括号表示法

最小表示法

括号表示法 

前提是:1-两两配对

              2-路径间不可能交叉

本题刚好满足 

例题:插头DP 

给你一个 n×m 的棋盘,有的格子是障碍,问共有多少条回路满足经过每个非障碍格子恰好一次。

如图,n=m=4,(1,1),(1,2) 是障碍,共有 2 条满足要求的回路。

输入格式

第一行包含两个整数 n,m。

接下来 n 行,每行包含一个长度为 m 的字符串,字符串中只包含 * 和 .,其中 * 表示障碍格子,. 表示非障碍格子。

输出格式

输出一个整数,表示满足条件的回路数量。

数据范围

2 ≤ n,m ≤ 12

输入样例:

  1. 4 4
  2. **..
  3. ....
  4. ....
  5. ....

输出样例:

2

核心:枚举每个状态

提示:状态五在改变之前x,y均是1,但因为两条边不能交叉,所以两条出边必然连在一起,则x,y不再满足是路径的左端,所以不是1,而右边分别变为1,2

  1. #include<iostream>
  2. #include<cstring>
  3. using namespace std;
  4. typedef long long ll;
  5. const int N=50000,M=N*2+7;
  6. int n,m,end_x,end_y;
  7. int g[20][20],q[2][N],cnt[N];//q有效状态在哈希表下标,cnt有效数量
  8. int h[2][M];
  9. ll v[2][M];//方案数
  10. int find(int cur,int x)//开放寻址法
  11. {
  12. int t=x%M;
  13. while(h[cur][t]!=-1&&h[cur][t]!=x)
  14. if(++t==M)
  15. t=0;
  16. return t;
  17. }
  18. void insert(int cur,int state,ll w)//当前滚动插入state,数量是w
  19. {
  20. int t=find(cur,state);
  21. if(h[cur][t]==-1)
  22. {
  23. h[cur][t]=state,v[cur][t]=w;
  24. q[cur][++cnt[cur]]=t;
  25. }
  26. else
  27. v[cur][t]+=w;
  28. }
  29. int get(int state,int k)//求第k个格子的状态,实际求四进制的第k位数字
  30. {
  31. return state>>k*2&3;
  32. }
  33. int set(int k,int v)//构造四进制的第k位数字为v的数
  34. {
  35. return v*(1<<k*2);
  36. }
  37. int main()
  38. {
  39. cin>>n>>m;
  40. for(int i=1;i<=n;i++)
  41. {
  42. char str[20];
  43. scanf("%s",str+1);
  44. for(int j=1;j<=m;j++)
  45. {
  46. if(str[j]=='.')
  47. {
  48. g[i][j]=1;
  49. end_x=i,end_y=j;
  50. }
  51. }
  52. }
  53. ll res=0;
  54. memset(h,-1,sizeof h);
  55. int cur=0;//滚动数组
  56. insert(cur,0,1);//初始状态,方案数
  57. for(int i=1;i<=n;i++)
  58. {
  59. for(int j=1;j<=cnt[cur];j++)//处理换行
  60. {
  61. h[cur][q[cur][j]]<<=2;
  62. }
  63. for(int j=1;j<=m;j++)//枚举每个格子
  64. {
  65. int last=cur;//上一次滚动的
  66. cur^=1,cnt[cur]=0;
  67. memset(h[cur],-1,sizeof h[cur]);
  68. for(int k=1;k<=cnt[last];k++)//枚举有效状态
  69. {
  70. int state=h[last][q[last][k]];
  71. ll w=v[last][q[last][k]];
  72. int x=get(state,j-1),y=get(state,j);
  73. if(!g[i][j])
  74. {
  75. if(!x&&!y)
  76. insert(cur,state,w);
  77. }
  78. else if(!x&&!y)
  79. {
  80. if(g[i+1][j]&&g[i][j+1])
  81. insert(cur,state+set(j-1,1)+set(j,2),w);
  82. }
  83. else if(!x&&y)
  84. {
  85. if(g[i][j+1])
  86. insert(cur,state,w);
  87. if(g[i+1][j])
  88. insert(cur,state+set(j-1,y)-set(j,y),w);
  89. }
  90. else if(x&&!y)
  91. {
  92. if(g[i][j+1])
  93. insert(cur,state-set(j-1,x)+set(j,x),w);
  94. if(g[i+1][j])
  95. insert(cur,state,w);
  96. }
  97. else if(x==1&&y==1)
  98. {
  99. for(int u=j+1,s=1;;u++)
  100. {
  101. int z=get(state,u);
  102. if(z==1)
  103. s++;
  104. else if(z==2)
  105. {
  106. if(--s==0)
  107. {
  108. insert(cur,state-set(j-1,x)-set(j,y)-set(u,1),w);
  109. break;
  110. }
  111. }
  112. }
  113. }
  114. else if(x==2&&y==2)
  115. {
  116. for(int u=j-2,s=1;;u--)//找匹配
  117. {
  118. int z=get(state,u);
  119. if(z==2)
  120. s++;
  121. else if(z==1)
  122. {
  123. if(--s==0)
  124. {
  125. insert(cur,state-set(j-1,x)-set(j,y)+set(u,1),w);
  126. break;
  127. }
  128. }
  129. }
  130. }
  131. else if(x==2&&y==1)
  132. {
  133. insert(cur,state-set(j-1,x)-set(j,y),w);
  134. }
  135. else if(i==end_x&&j==end_y)
  136. res+=w;
  137. }
  138. }
  139. }
  140. cout<<res<<endl;
  141. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/50915
推荐阅读
相关标签
  

闽ICP备14008679号