【宽度优先搜索】神奇的状态压缩 CodeVs1004四子连棋
一、写在前面
其实这是一道大水题,而且还出在了数据最水的OJ上,所以实际上这题并没有什么难度。博主写这篇blog主要是想写下一个想法——状态压缩。状态压缩在记录、修改状态以及判重去重等方面有着极高的(←_←词穷了,诸位大致理解一下就好)效率。博主原本打算在blog介绍一种DP——状态压缩型动态规划,但动笔(键盘??)前,博主突然想起自己前些年写过的一道广搜题,当时在判重方面冥思苦想想出了一种类似状态压缩的方法,开心了好久,于是在此先抛砖引玉为状压DP做个铺垫。
二、题目
Description
在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。
Input Description
从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。
Output Description
用最少的步数移动到目标棋局的步数。
Sample Input
BWBO
WBWB
BWBW
WBWO
Sample Output
5
原题链接→_→:|1004 四子连棋|CODEVS,算法爱好者社区
三、题目分析
大体思路大家都懂,一个中规中矩的广搜没什么好说的,主要来说说状态压缩。我们知道由于不同的棋盘状态经过不同的操作后可能得到同一张棋盘,所以为了节省空间和时间,我们需要进行判重操作——即如果一个棋盘状态已经如果队了,我们不会将其第二次入队。然而如何存储棋盘状态成了一个问题,这时我们就需要用到神奇的状态压缩了。我们发现,一个棋盘中有且仅有三种元素,我们不妨规定0代表空格,1代表白棋,2代表黑棋。如此一来,每张棋盘都被转化成了一个独一无二的三进制数,每个三进制数转化成十进制数就便于我们存储了;而当我们需要使用这些被存储的状态时,我们只需要把十进制再转回三进制即可。如样例棋盘对应的三进制数就是2120121221211210。
四、代码实现
幼年期代码真的辣眼睛,各位看官凑合着看吧_(:з」∠)_
1 #include<stdio.h> 2 int map[5][5]; 3 bool vis[44000000]; 4 int q[100000],l,r; 5 int step[100000]; 6 int col[100000]; 7 int x[3],y[3],mark; 8 void input() 9 { 10 char k[10]; 11 int p,q; 12 for(p=1;p<=4;p++) 13 { 14 scanf("%s",k); 15 for(q=0;q<=3;q++) 16 { 17 if(k[q]=='O') 18 { 19 map[p][q+1]=0; 20 } 21 if(k[q]=='W') 22 { 23 map[p][q+1]=1; 24 } 25 if(k[q]=='B') 26 { 27 map[p][q+1]=2; 28 } 29 } 30 } 31 } 32 int trans()//把棋盘转成十进制数存储 33 { 34 int i,j; 35 int cnt=1,ans=0; 36 for(i=4;i>=1;i--) 37 { 38 for(j=4;j>=1;j--) 39 { 40 ans+=map[i][j]*cnt; 41 cnt*=3; 42 } 43 } 44 return ans; 45 } 46 bool check() 47 { 48 if(map[1][1]==map[2][2]&&map[2][2]==map[3][3]&&map[3][3]==map[4][4])return true; 49 if(map[1][4]==map[2][3]&&map[2][3]==map[3][2]&&map[3][2]==map[4][1])return true; 50 int i; 51 for(i=1;i<=4;i++) 52 { 53 if(map[1][i]==map[2][i]&&map[2][i]==map[3][i]&&map[3][i]==map[4][i])return true; 54 if(map[i][1]==map[i][2]&&map[i][2]==map[i][3]&&map[i][3]==map[i][4])return true; 55 } 56 return false; 57 } 58 void reset(int num)//把十进制数转成三进制还原棋盘 59 { 60 int i,j; 61 for(i=4;i>=1;i--) 62 { 63 for(j=4;j>=1;j--) 64 { 65 map[i][j]=num%3; 66 num/=3; 67 } 68 } 69 } 70 void bfs() 71 { 72 int i,j; 73 int num; 74 while(l<=r) 75 { 76 mark=0; 77 reset(q[l]); 78 if(check()) 79 { 80 return; 81 } 82 for(i=1;i<=4;i++) 83 { 84 for(j=1;j<=4;j++) 85 { 86 if(!map[i][j]) 87 { 88 x[++mark]=i; 89 y[mark]=j; 90 } 91 } 92 } 93 if((x[1]!=1&&col[l]==0)||(x[1]!=1&&map[x[1]-1][y[1]]==3-col[l])) 94 { 95 map[x[1]][y[1]]=map[x[1]-1][y[1]]; 96 map[x[1]-1][y[1]]=0; 97 num=trans(); 98 if(vis[num]) 99 { 100 map[x[1]-1][y[1]]=map[x[1]][y[1]]; 101 map[x[1]][y[1]]=0; 102 } 103 else 104 { 105 vis[num]=true; 106 q[++r]=num; 107 step[r]=step[l]+1; 108 col[r]=map[x[1]][y[1]]; 109 map[x[1]-1][y[1]]=map[x[1]][y[1]]; 110 map[x[1]][y[1]]=0; 111 } 112 } 113 if(col[l]==0||map[x[1]+1][y[1]]==3-col[l]) 114 { 115 map[x[1]][y[1]]=map[x[1]+1][y[1]]; 116 map[x[1]+1][y[1]]=0; 117 num=trans(); 118 if(vis[num]) 119 { 120 map[x[1]+1][y[1]]=map[x[1]][y[1]]; 121 map[x[1]][y[1]]=0; 122 } 123 else 124 { 125 vis[num]=true; 126 q[++r]=num; 127 step[r]=step[l]+1; 128 col[r]=map[x[1]][y[1]]; 129 map[x[1]+1][y[1]]=map[x[1]][y[1]]; 130 map[x[1]][y[1]]=0; 131 } 132 } 133 if((y[1]!=1&&col[l]==0)||(y[1]!=1&&map[x[1]][y[1]-1]==3-col[l])) 134 { 135 map[x[1]][y[1]]=map[x[1]][y[1]-1]; 136 map[x[1]][y[1]-1]=0; 137 num=trans(); 138 if(vis[num]) 139 { 140 map[x[1]][y[1]-1]=map[x[1]][y[1]]; 141 map[x[1]][y[1]]=0; 142 } 143 else 144 { 145 vis[num]=true; 146 q[++r]=num; 147 step[r]=step[l]+1; 148 col[r]=map[x[1]][y[1]]; 149 map[x[1]][y[1]-1]=map[x[1]][y[1]]; 150 map[x[1]][y[1]]=0; 151 } 152 } 153 if(col[l]==0||map[x[1]][y[1]+1]==3-col[l]) 154 { 155 map[x[1]][y[1]]=map[x[1]][y[1]+1]; 156 map[x[1]][y[1]+1]=0; 157 num=trans(); 158 if(vis[num]) 159 { 160 map[x[1]][y[1]+1]=map[x[1]][y[1]]; 161 map[x[1]][y[1]]=0; 162 } 163 else 164 { 165 vis[num]=true; 166 q[++r]=num; 167 step[r]=step[l]+1; 168 col[r]=map[x[1]][y[1]]; 169 map[x[1]][y[1]+1]=map[x[1]][y[1]]; 170 map[x[1]][y[1]]=0; 171 } 172 } 173 if((x[2]!=1&&col[l]==0)||(x[2]!=1&&map[x[2]-1][y[2]]==3-col[l])) 174 { 175 map[x[2]][y[2]]=map[x[2]-1][y[2]]; 176 map[x[2]-1][y[2]]=0; 177 num=trans(); 178 if(vis[num]) 179 { 180 map[x[2]-1][y[2]]=map[x[2]][y[2]]; 181 map[x[2]][y[2]]=0; 182 } 183 else 184 { 185 vis[num]=true; 186 q[++r]=num; 187 step[r]=step[l]+1; 188 col[r]=map[x[2]][y[2]]; 189 map[x[2]-1][y[2]]=map[x[2]][y[2]]; 190 map[x[2]][y[2]]=0; 191 } 192 } 193 if(col[l]==0||map[x[2]+1][y[2]]==3-col[l]) 194 { 195 map[x[2]][y[2]]=map[x[2]+1][y[2]]; 196 map[x[2]+1][y[2]]=0; 197 num=trans(); 198 if(vis[num]) 199 { 200 map[x[2]+1][y[2]]=map[x[2]][y[2]]; 201 map[x[2]][y[2]]=0; 202 } 203 else 204 { 205 vis[num]=true; 206 q[++r]=num; 207 step[r]=step[l]+1; 208 col[r]=map[x[2]][y[2]]; 209 map[x[2]+1][y[2]]=map[x[2]][y[2]]; 210 map[x[2]][y[2]]=0; 211 } 212 } 213 if((y[2]!=1&&col[l]==0)||(y[2]!=1&&map[x[2]][y[2]-1]==3-col[l])) 214 { 215 map[x[2]][y[2]]=map[x[2]][y[2]-1]; 216 map[x[2]][y[2]-1]=0; 217 num=trans(); 218 if(vis[num]) 219 { 220 map[x[2]][y[2]-1]=map[x[2]][y[2]]; 221 map[x[2]][y[2]]=0; 222 } 223 else 224 { 225 vis[num]=true; 226 q[++r]=num; 227 step[r]=step[l]+1; 228 col[r]=map[x[2]][y[2]]; 229 map[x[2]][y[2]-1]=map[x[2]][y[2]]; 230 map[x[2]][y[2]]=0; 231 } 232 } 233 if(col[l]==0||map[x[2]][y[2]+1]==3-col[l]) 234 { 235 map[x[2]][y[2]]=map[x[2]][y[2]+1]; 236 map[x[2]][y[2]+1]=0; 237 num=trans(); 238 if(vis[num]) 239 { 240 map[x[2]][y[2]+1]=map[x[2]][y[2]]; 241 map[x[2]][y[2]]=0; 242 } 243 else 244 { 245 vis[num]=true; 246 q[++r]=num; 247 step[r]=step[l]+1; 248 col[r]=map[x[2]][y[2]]; 249 map[x[2]][y[2]+1]=map[x[2]][y[2]]; 250 map[x[2]][y[2]]=0; 251 } 252 } 253 l++; 254 } 255 } 256 int main() 257 { 258 int i,j; 259 input(); 260 int num=trans(); 261 vis[num]=true; 262 l=1; 263 r=1; 264 q[1]=num; 265 bfs(); 266 printf("%d",step[l]); 267 return 0; 268 }
弱弱地说一句,本蒟蒻码字也不容易,转载请注明出处http://www.cnblogs.com/Maki-Nishikino/p/5991570.html