现在的位置: 首页 > 综合 > 正文

双向搜索+hash poj 3131 双向搜索+hash判重

2017年11月05日 ⁄ 综合 ⁄ 共 9882字 ⁄ 字号 评论关闭

poj 3131 双向搜索+hash判重

分类:
搜索

136人阅读
评论(0)
收藏
举报

题意:

初始状态固定(朝上的全是W,空格位置输入给出),输入初始状态的空格位置,和最终状态朝上的位置,输出要多少步才能移动到,超过30步输出-1.

简析:

每一个格子有6种状态,分别是

0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR (上前后 对应的颜色)

由于只给出了终态朝上的颜色,其他的不知道,所以终态真正应该有256种,对于这个可以用一次dfs全部枚举出。

一、

搜索策略的问题

单向搜索的话,平均一下,大概每次也有3个状态,30层的话,复杂度太高,放弃。

A*的话,考虑当前不在正确位置的格子数。不知道是否可行,没有尝试。

双向搜索的话,只有30层,平分一下15层,再看看时间5s,还是可以接受的。而考虑到最终状态有256个,所以反向扩展的速度非常快,所以我们可以让

反向搜索只进行10层左右,保持2边平衡达到最佳速度。

二、

考虑判重的问题

由上面的分析可知,判重可以选择2种方式。

1、用一个6进制可以存下所有非空格的情况,再加一个空格的位置也就是6^8*9=15116544这么大的数组,双向搜索的话,也就是这个的2倍大的数组。

2、用一个7进制存下所有情况7^9-1=40353607,双向搜索的话,就是2倍………接近1亿。

第二种果断放弃了。。。

三、

hash值计算的问题

显然初始情况的hash要 s[0]*6^0+s[1]*6^1+......,但如果以后每次我们都用一个for(0---9)的循环计算的话,时间复杂度太高。

分析后发,每移动一次,左右移动的话,只会改变1个位置的值,上下移动的话只会改变3个位置的值,所以我们就计算这几个改变的值就够了。

四、

STL的使用,我测试了一下,不用STL的话速度可以快1000ms左右,但是内存就不好把握了,在上面都考虑到的情况下,用STL也不会影响AC。

给出STL版本的

  1. include<cstdio>
  2. #include<cstring>
  3. #include<queue>
  4. #include<iostream>
  5. #include<algorithm>
  6. using namespace std; // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR
  7. int base[]={1,6,36,216,1296,7776,46656,279936,1679616};
  8. int state[6][4]={{2,2,4,4},{5,5,3,3},{0,0,5,5},{4,4,1,1},{3,3,0,0},{1,1,2,2}};
  9. char hash1[1680000][9];
  10. char hash2[1680000][9];
  11. char b[10];
  12. struct node
  13. {
  14. int s[9];
  15. int dis;
  16. int space;
  17. int value;
  18. }st;
  19. queue<node> q;
  20. int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //下,上,右,左,和前面相反
  21. inline bool isok(int &x,int &y)
  22. {
  23. return x>=0&&x<3&&y>=0&&y<3;
  24. }
  25. inline int cal(node &t) //计算初始的hash值
  26. {
  27. int value=0;
  28. int top=0;
  29. for(int i=0;i<9;i++)
  30. {
  31. if(i==t.space) continue;
  32. value+=t.s[i]*base[top++];
  33. }
  34. return value;
  35. }
  36. int cal(node &t,node &f,int d) //因为每次移动只会改变几个hash值,所以可以特判
  37. {
  38. if(d==2)
  39. {
  40. t.value-=f.s[t.space]*base[f.space];
  41. t.value+=t.s[f.space]*base[f.space];
  42. return t.value;
  43. }
  44. else if(d==3)
  45. {
  46. t.value-=f.s[t.space]*base[t.space];
  47. t.value+=t.s[f.space]*base[t.space];
  48. return t.value;
  49. }
  50. else if(d==0)
  51. {
  52. for(int i=f.space;i<=f.space+2;i++)
  53. {
  54. t.value-=f.s[i+1]*base[i];
  55. t.value+=t.s[i]*base[i];
  56. }
  57. return t.value;
  58. }
  59. else if(d==1)
  60. {
  61. for(int i=t.space;i<=t.space+2;i++)
  62. {
  63. t.value-=f.s[i]*base[i];
  64. t.value+=t.s[i+1]*base[i];
  65. }
  66. return t.value;
  67. }
  68. }
  69. bool bfs(node st)
  70. {
  71. node t1,t2,f;
  72. queue<node> Q;
  73. st.dis=0;
  74. Q.push(st);
  75. t2.dis=0;
  76. int k;
  77. int k1=1,kk1=0,k2=256,kk2=0;
  78. while(!Q.empty()&&!q.empty())
  79. {
  80. while(k1--){
  81. st=Q.front();Q.pop();
  82. if(st.dis+1+t2.dis>30) {printf("-1\n");return false;}
  83. for(int d=0;d<4;d++)
  84. {
  85. t1=st;
  86. int sx=t1.space/3;
  87. int sy=t1.space%3;
  88. int nx=sx+dir[d][0];
  89. int ny=sy+dir[d][1];
  90. if(isok(nx,ny))
  91. {
  92. t1.space=nx*3+ny;
  93. t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];
  94. t1.s[nx*3+ny]=6;
  95. t1.dis=st.dis+1;
  96. t1.value=cal(t1,st,d);
  97. if(hash1[t1.value][t1.space]) continue;
  98. if(hash2[t1.value][t1.space]) {printf("%d\n",t1.dis+t2.dis);return true;}
  99. hash1[t1.value][t1.space]=t1.dis;
  100. Q.push(t1);
  101. kk1++;
  102. }
  103. }
  104. }
  105. k1=kk1;
  106. kk1=0;
  107. while(k2--){
  108. f=q.front();
  109. if(f.dis==9) break;
  110. q.pop();
  111. for(int d=0;d<4;d++)
  112. {
  113. t2=f;
  114. int sx=t2.space/3;
  115. int sy=t2.space%3;
  116. int nx=sx+dir[d][0];
  117. int ny=sy+dir[d][1];
  118. t2.dis=f.dis+1;
  119. if(isok(nx,ny))
  120. {
  121. t2.space=nx*3+ny;
  122. t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];
  123. t2.s[nx*3+ny]=6;
  124. t2.value=cal(t2,f,d);
  125. if(hash2[t2.value][t2.space]) continue;
  126. if(hash1[t2.value][t2.space])
  127. {
  128. printf("%d\n",t2.dis+st.dis+1);
  129. return true;
  130. }
  131. hash2[t2.value][t2.space]=t2.dis;
  132. q.push(t2);
  133. kk2++;
  134. }
  135. }
  136. }
  137. t1.dis=f.dis+1;
  138. k2=kk2;
  139. kk2=0;
  140. }
  141. printf("-1\n");
  142. }
  143. void dfs(node &end,int k)
  144. {
  145. if(k==9)
  146. {
  147. end.dis=0;
  148. end.value=cal(end);
  149. q.push(end);
  150. hash2[end.value][end.space]=1;
  151. return;
  152. }
  153. if(b[k]=='W')
  154. {
  155. end.s[k]=0;
  156. dfs(end,k+1);
  157. end.s[k]=1;
  158. dfs(end,k+1);
  159. }
  160. else if(b[k]=='R')
  161. {
  162. end.s[k]=2;
  163. dfs(end,k+1);
  164. end.s[k]=3;
  165. dfs(end,k+1);
  166. }
  167. else if(b[k]=='B')
  168. {
  169. end.s[k]=4;
  170. dfs(end,k+1);
  171. end.s[k]=5;
  172. dfs(end,k+1);
  173. }
  174. else
  175. {
  176. end.s[k]=6;
  177. dfs(end,k+1);
  178. }
  179. }
  180. int main()
  181. {
  182. int x,y;
  183. char a;
  184. node end;
  185. while(scanf("%d%d",&y,&x)!=EOF)
  186. {
  187. if(!x&&!y) break;
  188. while(!q.empty()) q.pop();
  189. memset(hash1,0,sizeof(hash1));
  190. memset(hash2,0,sizeof(hash2));
  191. x--;y--;
  192. for(int i=0;i<9;i++)
  193. {
  194. if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}
  195. else st.s[i]=0;
  196. }
  197. for(int i=0;i<9;i++)
  198. {
  199. scanf(" %c",&a);
  200. if(a=='E') end.space=i;
  201. b[i]=a;
  202. }
  203. dfs(end,0); //得到所有的终点状态,全部加入队列。
  204. int k; //一开始就是答案
  205. st.value=cal(st);
  206. hash1[st.value][st.space]=-1;
  207. if(hash2[st.value][st.space]) {printf("0\n");continue;}
  208. bfs(st);
  209. }
  210. return 0;
  211. }

再给出静态数组版本

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. using namespace std; // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR
  6. int base[]={1,6,36,216,1296,7776,46656,279936,1679616};
  7. int state[6][4]={{2,2,4,4},{5,5,3,3},{0,0,5,5},{4,4,1,1},{3,3,0,0},{1,1,2,2}};
  8. char hash1[1680000][9];
  9. char hash2[1680000][9];
  10. char b[10];
  11. struct node
  12. {
  13. int s[9];
  14. int dis;
  15. int space;
  16. int value;
  17. }q1[300000],q2[100005],st;
  18. int r2;
  19. int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //下,上,右,左,和前面相反
  20. inline bool isok(int &x,int &y)
  21. {
  22. return x>=0&&x<3&&y>=0&&y<3;
  23. }
  24. inline int cal(node &t) //计算初始的hash值
  25. {
  26. int value=0;
  27. int top=0;
  28. for(int i=0;i<9;i++)
  29. {
  30. if(i==t.space) continue;
  31. value+=t.s[i]*base[top++];
  32. }
  33. return value;
  34. }
  35. int cal(node &t,node &f,int d) //因为每次移动只会改变几个hash值,所以可以特判
  36. {
  37. if(d==2)
  38. {
  39. t.value-=f.s[t.space]*base[f.space];
  40. t.value+=t.s[f.space]*base[f.space];
  41. return t.value;
  42. }
  43. else if(d==3)
  44. {
  45. t.value-=f.s[t.space]*base[t.space];
  46. t.value+=t.s[f.space]*base[t.space];
  47. return t.value;
  48. }
  49. else if(d==0)
  50. {
  51. for(int i=f.space;i<=f.space+2;i++)
  52. {
  53. t.value-=f.s[i+1]*base[i];
  54. t.value+=t.s[i]*base[i];
  55. }
  56. return t.value;
  57. }
  58. else if(d==1)
  59. {
  60. for(int i=t.space;i<=t.space+2;i++)
  61. {
  62. t.value-=f.s[i]*base[i];
  63. t.value+=t.s[i+1]*base[i];
  64. }
  65. return t.value;
  66. }
  67. }
  68. bool bfs(node st)
  69. {
  70. node t1,t2,f;
  71. int r1=0,f1=0,f2=0;
  72. st.dis=0;
  73. q1[r1++]=st;
  74. t2.dis=0;
  75. int k;
  76. int k1=1,kk1=0,k2=256,kk2=0;
  77. while(f1<r1&&f2<r2)
  78. {
  79. while(k1--){
  80. st=q1[f1];
  81. if(st.dis+1+t2.dis>30) {printf("-1\n");return false;}
  82. for(int d=0;d<4;d++)
  83. {
  84. t1=st;
  85. int sx=t1.space/3;
  86. int sy=t1.space%3;
  87. int nx=sx+dir[d][0];
  88. int ny=sy+dir[d][1];
  89. if(isok(nx,ny))
  90. {
  91. t1.space=nx*3+ny;
  92. t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];
  93. t1.s[nx*3+ny]=6;
  94. t1.dis=st.dis+1;
  95. t1.value=cal(t1,st,d);
  96. if(hash1[t1.value][t1.space]) continue;
  97. if(hash2[t1.value][t1.space]) {printf("%d\n",t1.dis+t2.dis);return true;}
  98. hash1[t1.value][t1.space]=t1.dis;
  99. q1[r1++]=t1;
  100. kk1++;
  101. }
  102. }
  103. f1++;
  104. }
  105. k1=kk1;
  106. kk1=0;
  107. while(k2--){
  108. f=q2[f2];
  109. if(f.dis==8) break; //超过这个,反向就不搜了,
  110. for(int d=0;d<4;d++)
  111. {
  112. t2=f;
  113. int sx=t2.space/3;
  114. int sy=t2.space%3;
  115. int nx=sx+dir[d][0];
  116. int ny=sy+dir[d][1];
  117. t2.dis=f.dis+1;
  118. if(isok(nx,ny))
  119. {
  120. t2.space=nx*3+ny;
  121. t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];
  122. t2.s[nx*3+ny]=6;
  123. t2.value=cal(t2,f,d);
  124. if(hash2[t2.value][t2.space]) continue;
  125. if(hash1[t2.value][t2.space])
  126. {
  127. printf("%d\n",t2.dis+st.dis+1);
  128. return true;
  129. }
  130. hash2[t2.value][t2.space]=t2.dis;
  131. q2[r2++]=t2;
  132. kk2++;
  133. }
  134. }
  135. f2++;
  136. }
  137. t1.dis=f.dis+1;
  138. k2=kk2;
  139. kk2=0;
  140. }
  141. printf("-1\n");
  142. }
  143. void dfs(node &end,int k)
  144. {
  145. if(k==9)
  146. {
  147. end.dis=0;
  148. end.value=cal(end);
  149. q2[r2++]=end;
  150. hash2[end.value][end.space]=1;
  151. return;
  152. }
  153. if(b[k]=='W')
  154. {
  155. end.s[k]=0;
  156. dfs(end,k+1);
  157. end.s[k]=1;
  158. dfs(end,k+1);
  159. }
  160. else if(b[k]=='R')
  161. {
  162. end.s[k]=2;
  163. dfs(end,k+1);
  164. end.s[k]=3;
  165. dfs(end,k+1);
  166. }
  167. else if(b[k]=='B')
  168. {
  169. end.s[k]=4;
  170. dfs(end,k+1);
  171. end.s[k]=5;
  172. dfs(end,k+1);
  173. }
  174. else
  175. {
  176. end.s[k]=6;
  177. dfs(end,k+1);
  178. }
  179. }
  180. int main()
  181. {
  182. int x,y;
  183. char a;
  184. node end;
  185. while(scanf("%d%d",&y,&x)!=EOF)
  186. {
  187. if(!x&&!y) break;
  188. memset(hash1,0,sizeof(hash1));
  189. memset(hash2,0,sizeof(hash2));
  190. r2=0;
  191. x--;y--;
  192. for(int i=0;i<9;i++)
  193. {
  194. if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}
  195. else st.s[i]=0;
  196. }
  197. for(int i=0;i<9;i++)
  198. {
  199. scanf(" %c",&a);
  200. if(a=='E') end.space=i;
  201. b[i]=a;
  202. }
  203. dfs(end,0); //得到所有的终点状态,全部加入队列。
  204. int k; //一开始就是答案
  205. st.value=cal(st);
  206. hash1[st.value][st.space]=-1;
  207. if(hash2[st.value][st.space]) {printf("0\n");continue;}
  208. bfs(st);
  209. }
  210. return 0;
  211. }

抱歉!评论已关闭.