poj 3131 双向搜索+hash判重
題意:
初始狀態固定(朝上的全是W,空格位置輸入給出),輸入初始狀態的空格位置,和最終狀態朝上的位置,輸出要多少步才能移動到,超過30步輸出-1.
簡析:
每一個格子有6種狀態,分別是
0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR (上前后 對應的顏色)
由于只給出了終態朝上的顏色,其他的不知道,所以終態真正應該有256種,對于這個可以用一次dfs全部枚舉出。
一、
?
搜索策略的問題
單向搜索的話,平均一下,大概每次也有3個狀態,30層的話,復雜度太高,放棄。
A*的話,考慮當前不在正確位置的格子數。不知道是否可行,沒有嘗試。
雙向搜索的話,只有30層,平分一下15層,再看看時間5s,還是可以接受的。而考慮到最終狀態有256個,所以反向擴展的速度非???#xff0c;所以我們可以讓
反向搜索只進行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版本的
?
include<cstdio> #include<cstring> #include<queue> #include<iostream> #include<algorithm> using namespace std; // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWRint base[]={1,6,36,216,1296,7776,46656,279936,1679616}; 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}}; char hash1[1680000][9]; char hash2[1680000][9]; char b[10]; struct node {int s[9];int dis;int space;int value; }st; queue<node> q; int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //下,上,右,左,和前面相反inline bool isok(int &x,int &y) {return x>=0&&x<3&&y>=0&&y<3; } inline int cal(node &t) //計算初始的hash值 {int value=0;int top=0;for(int i=0;i<9;i++){if(i==t.space) continue;value+=t.s[i]*base[top++];}return value; }int cal(node &t,node &f,int d) //因為每次移動只會改變幾個hash值,所以可以特判 {if(d==2){t.value-=f.s[t.space]*base[f.space];t.value+=t.s[f.space]*base[f.space];return t.value;}else if(d==3){t.value-=f.s[t.space]*base[t.space];t.value+=t.s[f.space]*base[t.space];return t.value;}else if(d==0){for(int i=f.space;i<=f.space+2;i++){t.value-=f.s[i+1]*base[i];t.value+=t.s[i]*base[i];}return t.value;}else if(d==1){for(int i=t.space;i<=t.space+2;i++){t.value-=f.s[i]*base[i];t.value+=t.s[i+1]*base[i];}return t.value;} } bool bfs(node st) {node t1,t2,f;queue<node> Q;st.dis=0;Q.push(st);t2.dis=0;int k;int k1=1,kk1=0,k2=256,kk2=0;while(!Q.empty()&&!q.empty()){while(k1--){st=Q.front();Q.pop();if(st.dis+1+t2.dis>30) {printf("-1\n");return false;}for(int d=0;d<4;d++){t1=st;int sx=t1.space/3;int sy=t1.space%3;int nx=sx+dir[d][0];int ny=sy+dir[d][1];if(isok(nx,ny)){t1.space=nx*3+ny;t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];t1.s[nx*3+ny]=6;t1.dis=st.dis+1;t1.value=cal(t1,st,d);if(hash1[t1.value][t1.space]) continue;if(hash2[t1.value][t1.space]) {printf("%d\n",t1.dis+t2.dis);return true;}hash1[t1.value][t1.space]=t1.dis;Q.push(t1);kk1++;}}}k1=kk1;kk1=0;while(k2--){f=q.front();if(f.dis==9) break;q.pop();for(int d=0;d<4;d++){t2=f;int sx=t2.space/3;int sy=t2.space%3;int nx=sx+dir[d][0];int ny=sy+dir[d][1];t2.dis=f.dis+1;if(isok(nx,ny)){t2.space=nx*3+ny;t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];t2.s[nx*3+ny]=6;t2.value=cal(t2,f,d);if(hash2[t2.value][t2.space]) continue;if(hash1[t2.value][t2.space]){printf("%d\n",t2.dis+st.dis+1);return true;}hash2[t2.value][t2.space]=t2.dis;q.push(t2);kk2++;}}}t1.dis=f.dis+1;k2=kk2;kk2=0;}printf("-1\n"); } void dfs(node &end,int k) {if(k==9){end.dis=0;end.value=cal(end);q.push(end);hash2[end.value][end.space]=1;return;}if(b[k]=='W'){end.s[k]=0;dfs(end,k+1);end.s[k]=1;dfs(end,k+1);}else if(b[k]=='R'){end.s[k]=2;dfs(end,k+1);end.s[k]=3;dfs(end,k+1);}else if(b[k]=='B'){end.s[k]=4;dfs(end,k+1);end.s[k]=5;dfs(end,k+1);}else{end.s[k]=6;dfs(end,k+1);} } int main() {int x,y;char a;node end;while(scanf("%d%d",&y,&x)!=EOF){if(!x&&!y) break;while(!q.empty()) q.pop();memset(hash1,0,sizeof(hash1));memset(hash2,0,sizeof(hash2));x--;y--;for(int i=0;i<9;i++){if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}else st.s[i]=0;}for(int i=0;i<9;i++){scanf(" %c",&a);if(a=='E') end.space=i;b[i]=a;}dfs(end,0); //得到所有的終點狀態,全部加入隊列。int k; //一開始就是答案st.value=cal(st);hash1[st.value][st.space]=-1;if(hash2[st.value][st.space]) {printf("0\n");continue;}bfs(st);}return 0; }
再給出靜態數組版本
?
?
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWRint base[]={1,6,36,216,1296,7776,46656,279936,1679616}; 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}}; char hash1[1680000][9]; char hash2[1680000][9]; char b[10]; struct node {int s[9];int dis;int space;int value; }q1[300000],q2[100005],st; int r2; int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //下,上,右,左,和前面相反inline bool isok(int &x,int &y) {return x>=0&&x<3&&y>=0&&y<3; } inline int cal(node &t) //計算初始的hash值 {int value=0;int top=0;for(int i=0;i<9;i++){if(i==t.space) continue;value+=t.s[i]*base[top++];}return value; }int cal(node &t,node &f,int d) //因為每次移動只會改變幾個hash值,所以可以特判 {if(d==2){t.value-=f.s[t.space]*base[f.space];t.value+=t.s[f.space]*base[f.space];return t.value;}else if(d==3){t.value-=f.s[t.space]*base[t.space];t.value+=t.s[f.space]*base[t.space];return t.value;}else if(d==0){for(int i=f.space;i<=f.space+2;i++){t.value-=f.s[i+1]*base[i];t.value+=t.s[i]*base[i];}return t.value;}else if(d==1){for(int i=t.space;i<=t.space+2;i++){t.value-=f.s[i]*base[i];t.value+=t.s[i+1]*base[i];}return t.value;} } bool bfs(node st) {node t1,t2,f;int r1=0,f1=0,f2=0;st.dis=0;q1[r1++]=st;t2.dis=0;int k;int k1=1,kk1=0,k2=256,kk2=0;while(f1<r1&&f2<r2){while(k1--){st=q1[f1];if(st.dis+1+t2.dis>30) {printf("-1\n");return false;}for(int d=0;d<4;d++){t1=st;int sx=t1.space/3;int sy=t1.space%3;int nx=sx+dir[d][0];int ny=sy+dir[d][1];if(isok(nx,ny)){t1.space=nx*3+ny;t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];t1.s[nx*3+ny]=6;t1.dis=st.dis+1;t1.value=cal(t1,st,d);if(hash1[t1.value][t1.space]) continue;if(hash2[t1.value][t1.space]) {printf("%d\n",t1.dis+t2.dis);return true;}hash1[t1.value][t1.space]=t1.dis;q1[r1++]=t1;kk1++;}}f1++;}k1=kk1;kk1=0;while(k2--){f=q2[f2];if(f.dis==8) break; //超過這個,反向就不搜了,for(int d=0;d<4;d++){t2=f;int sx=t2.space/3;int sy=t2.space%3;int nx=sx+dir[d][0];int ny=sy+dir[d][1];t2.dis=f.dis+1;if(isok(nx,ny)){t2.space=nx*3+ny;t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];t2.s[nx*3+ny]=6;t2.value=cal(t2,f,d);if(hash2[t2.value][t2.space]) continue;if(hash1[t2.value][t2.space]){printf("%d\n",t2.dis+st.dis+1);return true;}hash2[t2.value][t2.space]=t2.dis;q2[r2++]=t2;kk2++;}}f2++;}t1.dis=f.dis+1;k2=kk2;kk2=0;}printf("-1\n"); } void dfs(node &end,int k) {if(k==9){end.dis=0;end.value=cal(end);q2[r2++]=end;hash2[end.value][end.space]=1;return;}if(b[k]=='W'){end.s[k]=0;dfs(end,k+1);end.s[k]=1;dfs(end,k+1);}else if(b[k]=='R'){end.s[k]=2;dfs(end,k+1);end.s[k]=3;dfs(end,k+1);}else if(b[k]=='B'){end.s[k]=4;dfs(end,k+1);end.s[k]=5;dfs(end,k+1);}else{end.s[k]=6;dfs(end,k+1);} } int main() {int x,y;char a;node end;while(scanf("%d%d",&y,&x)!=EOF){if(!x&&!y) break;memset(hash1,0,sizeof(hash1));memset(hash2,0,sizeof(hash2));r2=0;x--;y--;for(int i=0;i<9;i++){if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}else st.s[i]=0;}for(int i=0;i<9;i++){scanf(" %c",&a);if(a=='E') end.space=i;b[i]=a;}dfs(end,0); //得到所有的終點狀態,全部加入隊列。int k; //一開始就是答案st.value=cal(st);hash1[st.value][st.space]=-1;if(hash2[st.value][st.space]) {printf("0\n");continue;}bfs(st);}return 0; }?
總結
以上是生活随笔為你收集整理的poj 3131 双向搜索+hash判重的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android TextView 属性设
- 下一篇: 算法练习:将字符串中所有的空格替换为'%