算法:BFS
//2014-02-05更新
*******************************2013-10-15*******************************
PS:被卡过2天。日期:2013-10-14 ~ 2013-10-15 17:28:21
此题卡了我一天,原因是宽搜时方向搞错= =(汗= =),而这个错误我竟然检查了好久= =!!
(大神不要笑,我用来超多的代码来实现= =是别人提交代码的5倍以上,,,200多行= =)
2014.01.02 PS: 我承认我是脑残了,现在已会写bfs,改天有时间修改下,下面这个程序很好的证明了我不会搜索= =
#include <iostream> #include <cstring> #include <queue> using namespace std; enum pa{NUL, LEFT, UP, RIGHT, DOWN}; //四个方向 enum color{O, W, B}; //白色用W表示,黑色用B表示,NUL就表示空格 struct st { color m[4][4]; short d; //次数 short x1, y1, x2, y2; //空格的位置 bool who; //0表示到白棋走,1表示黑棋走 pa p1, p2; //空格之前所在的位置,即以本格子来看从哪个位置是移动之前的状态 st& operator= (const st& s) { memcpy(m, s.m, sizeof(m)); d=s.d; who=s.who; p1=s.p1; p2=s.p2; x1=s.x1; x2=s.x2; y1=s.y1; y2=s.y2; return *this; } st(){memset(m, 0, sizeof(m)); d=0; x1=x2=y1=y2=-1; p1=p2=NUL; who=1;} }state; queue<st> q; int i, j; void readin() { char chartemp; for(i = 0; i < 4; i++) for(j = 0; j < 4; j++) { cin >> chartemp; if(chartemp == 'W') state.m[i][j] = W; else if(chartemp == 'B') state.m[i][j] = B; else { state.m[i][j] = O; if(state.x1 == -1) state.x1 = i, state.y1 = j; else state.x2 = i, state.y2 = j; } } } void chu() { st t = state; if(t.x1+1<4 && t.m[t.x1+1][t.y1] != O) //第一个空格 向下移 { t.p1 = UP; t.p2 = NUL; t.x1++; t.m[t.x1-1][t.y1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = t.m[t.x1-1][t.y1]-1; t.who = !t.who; q.push(t); } t = state; if(t.x2+1<4 && t.m[t.x2+1][t.y2] != O) //第二个空格 向下移 { t.p2 = UP; t.p1 = NUL; t.x2++; t.m[t.x2-1][t.y2] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = t.m[t.x2-1][t.y2]-1; t.who = !t.who; q.push(t); } t = state; if(t.y1+1<4 && t.m[t.x1][t.y1+1] != O) //第一个空格 向右移 { t.p1 = LEFT; t.p2 = NUL; t.y1++; t.m[t.x1][t.y1-1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = t.m[t.x1][t.y1-1]-1; t.who = !t.who; q.push(t); } t = state; if(t.y2+1<4 && t.m[t.x2][t.y2+1] != O) //第二个空格 向右移 { t.p2 = LEFT; t.p1 = NUL; t.y2++; t.m[t.x2][t.y2-1] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = t.m[t.x2][t.y2-1]-1; t.who = !t.who; q.push(t); } t = state; if(t.x1 > 0 && t.m[t.x1-1][t.y1] != O) //第一个空格 向上移 { t.p1 = DOWN; t.p2 = NUL; t.x1--; t.m[t.x1+1][t.y1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = t.m[t.x1+1][t.y1]-1; t.who = !t.who; q.push(t); } t = state; if(t.x2 > 0 && t.m[t.x2-1][t.y2] != O) //第二个空格 向上移 { t.p2 = DOWN; t.p1 = NUL; t.x2--; t.m[t.x2+1][t.y2] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = t.m[t.x2+1][t.y2]-1; t.who = !t.who; q.push(t); } t = state; if(t.y1 > 0 && t.m[t.x1][t.y1-1] != O) //第一个空格 向左移 { t.p1 = RIGHT; t.p2 = NUL; t.y1--; t.m[t.x1][t.y1+1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = t.m[t.x1][t.y1+1]-1; t.who = !t.who; q.push(t); } t = state; if(t.y2 > 0 && t.m[t.x2][t.y2-1] != O) //第二个空格 向左移 { t.p2 = RIGHT; t.p1 = NUL; t.y2--; t.m[t.x2][t.y2+1] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = t.m[t.x2][t.y2+1]-1; t.who = !t.who; q.push(t); } } bool check(const st& s) { int x, y; pa p; bool bp = 1; if(s.p1 != NUL) p = s.p1; else {p = s.p2; bp = 0;} switch(p) { case UP: x = (bp?s.x1-1:s.x2-1); y = (bp?s.y1:s.y2); break; case DOWN: x = (bp?s.x1+1:s.x2+1); y = (bp?s.y1:s.y2); break; case RIGHT: x = (bp?s.x1:s.x2); y = (bp?s.y1+1:s.y2+1); break; case LEFT: x = (bp?s.x1:s.x2); y = (bp?s.y1-1:s.y2-1); break; default: return 0; } if((s.m[x][0]==s.m[x][1]&&s.m[x][1]==s.m[x][2]&&s.m[x][2]==s.m[x][3]) || (s.m[0][y]==s.m[1][y]&&s.m[1][y]==s.m[2][y]&&s.m[2][y]==s.m[3][y]) || (s.m[0][0]==s.m[1][1]&&s.m[1][1]==s.m[2][2]&&s.m[2][2]==s.m[3][3]) || (s.m[0][3]==s.m[1][2]&&s.m[1][2]==s.m[2][1]&&s.m[2][1]==s.m[3][0]) ) return 1; return 0; } int main() { readin(); chu(); st s, t; int n = 0; //迭代 while(++n != 10000000) { s = q.front(); q.pop(); if(check(s)) break; t = s; // 要判断是否这个点是从原来方向移动得到的,如果要向上移,则p域就不能是下面,否则会大大损耗空间和时间 if(t.x1+1<4 && t.p1 != DOWN && t.m[t.x1+1][t.y1] != O && t.m[t.x1+1][t.y1]-1 == t.who) //第一个空格 向下移 { t.p1 = UP; t.p2 = NUL; t.x1++; t.m[t.x1-1][t.y1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who; q.push(t); } t = s; if(t.x2+1<4 && t.p2 != DOWN && t.m[t.x2+1][t.y2] != O && t.m[t.x2+1][t.y2]-1 == t.who) //第二个空格 向下移 { t.p2 = UP; t.p1 = NUL; t.x2++; t.m[t.x2-1][t.y2] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who; q.push(t); } t = s; if(t.y1+1<4 && t.p1 != RIGHT && t.m[t.x1][t.y1+1] != O && t.m[t.x1][t.y1+1]-1 == t.who) //第一个空格 向右移 { t.p1 = LEFT; t.p2 = NUL; t.y1++; t.m[t.x1][t.y1-1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who; q.push(t); } t = s; if(t.y2+1<4 && t.p2 != RIGHT && t.m[t.x2][t.y2+1] != O && t.m[t.x2][t.y2+1]-1 == t.who) //第二个空格 向右移 { t.p2 = LEFT; t.p1 = NUL; t.y2++; t.m[t.x2][t.y2-1] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who; q.push(t); } t = s; if(t.x1 > 0 && t.p1 != UP && t.m[t.x1-1][t.y1] != O && t.m[t.x1-1][t.y1]-1 == t.who) //第一个空格 向上移 { t.p1 = DOWN; t.p2 = NUL; t.x1--; t.m[t.x1+1][t.y1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who; q.push(t); } t = s; if(t.x2 > 0 && t.p2 != UP && t.m[t.x2-1][t.y2] != O && t.m[t.x2-1][t.y2]-1 == t.who) //第二个空格 向上移 { t.p2 = DOWN; t.p1 = NUL; t.x2--; t.m[t.x2+1][t.y2] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who; q.push(t); } t = s; if(t.y1 > 0 && t.p1 != LEFT && t.m[t.x1][t.y1-1] != O && t.m[t.x1][t.y1-1]-1 == t.who) //第一个空格 向左移 { t.p1 = RIGHT; t.p2 = NUL; t.y1--; t.m[t.x1][t.y1+1] = t.m[t.x1][t.y1]; t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who; q.push(t); } t = s; if(t.y2 > 0 && t.p2 != LEFT && t.m[t.x2][t.y2-1] != O && t.m[t.x2][t.y2-1]-1 == t.who) //第二个空格 向左移 { t.p2 = RIGHT; t.p1 = NUL; t.y2--; t.m[t.x2][t.y2+1] = t.m[t.x2][t.y2]; t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who; q.push(t); } } cout << s.d << endl; return 0; }
*******************************2014-02-05*******************************
算法:BFS+Hash判重
裸BFS后,看了题解,有 Hash判重 知识,可算长姿势了。
Hash判重:将图看成一串数字,我们可以发现,这可以当作n进制的数看待,那么hash就有着落了。。我们将这个n进制数转换为十禁止,再开个数组,就可以hash了
这题的图元素只有3个,那么我们就可以将它看成3进制数来做hash。
注意:做hash的时候的mod要用质数(自己想为什么),因为这个图的长度为16,有7个2,那么经过粗略计算,这个hash的mod在40700000的后面,自己写了个小prime判定,找出了一个质数 40700017,就用它了。
代码:
#include <iostream> #include <cstring> using namespace std; struct Map { int m[4][4], x1, x2, y1, y2; int ans, who; Map& operator= (Map& a) { memcpy(m, a.m, sizeof(a.m)); x1=a.x1; x2=a.x2; y1=a.y1; y2=a.y2; ans=a.ans; who=a.who; return *this; } }q[600009]; //我们模拟队列,开那么多应该够了吧。。不够就用循环队列 Map t; //作为全局temp const int mod = 40700017; bool Hash[mod]; bool check(int f) { //判断行和列 for(int i = 0; i < 4; ++i) if( (q[f].m[i][0]==q[f].m[i][1] && q[f].m[i][1]==q[f].m[i][2] && q[f].m[i][2]==q[f].m[i][3]) || (q[f].m[0][i]==q[f].m[1][i] && q[f].m[1][i]==q[f].m[2][i] && q[f].m[2][i]==q[f].m[3][i]) ) return true; //判断斜边 if( (q[f].m[0][0]==q[f].m[1][1] && q[f].m[1][1]==q[f].m[2][2] && q[f].m[2][2]==q[f].m[3][3]) || (q[f].m[0][3]==q[f].m[1][2] && q[f].m[1][2]==q[f].m[2][1] && q[f].m[2][1]==q[f].m[3][0]) ) return true; return false; } void swap(int x, int y, int xx, int yy, int w) { t.m[x][y] = t.m[xx][yy]; t.m[xx][yy] = 0; if(w == 1) t.x1 = xx, t.y1 = yy; else t.x2 = xx, t.y2 = yy; t.who = t.m[x][y]; } bool hash(Map& s) { //k是3^x次方的结果 int i, j, k = 1, h = 0; for(i = 0; i < 4; ++i) for(j = 0; j < 4; ++j) { h += s.m[i][j] * k; k *= 3; } h %= mod; if(Hash[h]) return false; Hash[h] = 1; return true; } void bfs() { int f = 0, l = 1; int x1, y1, x2, y2; while(f != l) { if(check(f)) { cout << q[f].ans; break; } q[f].ans++; x1 = q[f].x1; y1 = q[f].y1; x2 = q[f].x2; y2 = q[f].y2; //8种情况。。我承认可以简略代码的,但是算了。这样看起来壮观 >_< if(x1 > 0 && q[f].m[x1-1][y1] != q[f].who) { t = q[f]; swap(x1, y1, x1-1, y1, 1); if(hash(t)) q[l++] = t; } if(x1 < 3 && q[f].m[x1+1][y1] != q[f].who) { t = q[f]; swap(x1, y1, x1+1, y1, 1); if(hash(t)) q[l++] = t; } if(y1 > 0 && q[f].m[x1][y1-1] != q[f].who) { t = q[f]; swap(x1, y1, x1, y1-1, 1); if(hash(t)) q[l++] = t; } if(y1 < 3 && q[f].m[x1][y1+1] != q[f].who) { t = q[f]; swap(x1, y1, x1, y1+1, 1); if(hash(t)) q[l++] = t; } if(x2 > 0 && q[f].m[x2-1][y2] != q[f].who) { t = q[f]; swap(x2, y2, x2-1, y2, 2); if(hash(t)) q[l++] = t; } if(x2 < 3 && q[f].m[x2+1][y2] != q[f].who) { t = q[f]; swap(x2, y2, x2+1, y2, 2); if(hash(t)) q[l++] = t; } if(y2 > 0 && q[f].m[x2][y2-1] != q[f].who) { t = q[f]; swap(x2, y2, x2, y2-1, 2); if(hash(t)) q[l++] = t; } if(y2 < 3 && q[f].m[x2][y2+1] != q[f].who) { t = q[f]; swap(x2, y2, x2, y2+1, 2); if(hash(t)) q[l++] = t; } f++; } } int main() { char t; bool ok = 1; for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) { cin >> t; switch(t) { case 'B': q[0].m[i][j] = 2; break; case 'W': q[0].m[i][j] = 1; break; case 'O': q[0].m[i][j] = 0; if(ok) q[0].x1 = i, q[0].y1 = j, ok = 0; else q[0].x2 = i, q[0].y2 = j; break; } } bfs(); return 0; }