题目描述:
4*4棋盘内有黑(b:black)白(w:white)两色的棋子,用bw表示颜色,选择其中一个反转后,自己和自己上下左右四个方向的棋子均变色,最少反转次数使棋盘全白或全黑。
用户四个一行输入,输入完毕后,打印最少反转次数,不能则打印Impossible
算法分析:
广度搜索+枚举+位运算
一个棋子有两种情况,16个棋子,即棋盘有2的十六次方种情况,即65536,正好一个短整形,所以想到用一个短整形记录棋盘情况,16个位对应棋盘16格。
广度搜索使用非递归模式,速度快,用队列实现,元素短整形。
全部遍历一遍,剪枝掉重复搜索的情况。
(参考了大神的做法)
程序代码:
#include <iostream>
using namespace std;
#define MAX 65535
unsigned short myqueue[MAX];//用‘位’保存状态的数组
int myrear = 0, mytop = 0;//头尾指针
bool flag[MAX];//是否出现过
int num[MAX];//记录翻牌次数
void init();
unsigned short change(unsigned now, int i);
bool bfs();
int main(int argc, char *argv[])
{
init();
if (!bfs())
cout << "Impossible";
return 0;
}
void init()
{
unsigned short temp = 0;
char c;
for ( int i = 0; i < 16; i++)
{
cin >> c;
if (c == 'b')
temp |= (1<<i);
}
myqueue[myrear++] = temp;
flag[temp] = true;
}
unsigned short change(unsigned now, int i)
{
unsigned short temp = 0;
temp |= (1<<i);
if ((i+1)%4 != 0)//不是最右边
temp |= (1<<(i+1));
if (i%4 != 0)//不是最左边
temp |= (1<<(i-1));
if (i-4 >= 0)//不是最上边
temp |= (1<<(i-4));
if (i+4 < 16)//不是最下边
temp |= (1<<(i+4));
return now ^ temp;
}
bool bfs()
{
while (myrear > mytop)
{
unsigned short former = myqueue[mytop++];
for ( int i = 0; i < 16; i++)
{
unsigned short temp = change(former, i);
if (former == 0 || former == 65535)
{
cout << num[former];
return true;
}
else if (!flag[temp])//剪枝,防重搜索
{
myqueue[myrear++] = temp;
flag[temp] = true;
num[temp] = num[former]+1;
}
}
}
return false;
}