广搜的问题,重点是位运算的应用。每翻转一个状态就对应一个16位的二进制数。翻转一次就是把某个数上下左右四个位置的棋子都翻转,即0->1,1->0。
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 26891 | Accepted: 11647 |
Description
Input
Output
Sample Input
bwwb bbwb bwwb bwww
Sample Output
4
#include
#include
using namespace std;
queue q;
bool flag[0x10000];
int step[0x10000];
int calculate(int num,int i) //num为当前状态对应的数,i为第几位
{
int p = 1 << i; //p左移i位
if(i % 4 != 0) //不是最右边一列
p |= 1 << (i - 1); //翻转右边的棋子
if((i + 1) % 4 != 0) //不是最左边一列
p |= 1 << (i + 1); //翻转左边的棋子
if(i > 3) //不是最下边一行
p |= 1 << (i - 4); //翻转下边的棋子
if(i < 12) //不是最上边一行
p |= 1 << (i + 4); //翻转上边的棋子
return num ^ p; //^是按位异或
}
int bfs()
{
while(!q.empty())//队非空
{
int num = q.front();//对头元素
q.pop();
int i;
for(i=0; i<16; i++)//循环16次
{
int new_num = calculate(num, i);//下一个状态
if(flag[new_num] != 1)//未标记过
{
if(new_num == 0 || new_num == 0xffff)//终止条件,即全白或全黑
return step[num] + 1;
q.push(new_num);//进队
flag[new_num] = 1;//标记
step[new_num] = step[num] + 1;//步数累加
}
}
}
return -1;//未翻到目标状态,则返回-1
}
int main()
{
char ch;
int num = 0;
int i = 16;
while(i --)
{
scanf("%c",&ch);
if(ch == '\n' || ch == ' ')//遇到换行和空格,不记录,i相应++
{
i ++;
continue;
}
num <<= 1;//num左移1位
if(ch == 'w')//如果是w,即白色,则num相应位置记为1
num ++;
}
flag[num] = 1;//当前状态,标记数组记为1
q.push(num);
step[num] = 0;
if(num == 0 || num == 0xffff)
{
printf("0\n");
return 0;
}
int t = bfs();
if(t != -1)
printf("%d\n",t);
else
printf("Impossible\n");
return 0;
}
15 | 14 | 13 | 12 |
11 | 10 | 9 | 8 |
7 | 6 | 5 | 4 |
3 | 2 | 1 | 0 |