题意:每次翻一个棋子会带动周围棋子翻面,问需要的最小翻棋次数使得棋盘颜色一致。
分析:棋盘上有16个棋子,分别对应二进制数的16-1位,用1表示black或white,这样一个整数value就可以表示一种棋盘状态。
每次翻棋可以用异或^进行,然后在value的基础上进行搜索。
/*输入方式一*/
// int k = 0;
// for (int i = 0; i < 4; ++i){
// for (int j = 0; j < 4; ++j){
// cin >> atlas[i][j];
// if(atlas[i][j] == 'b') value += 1<<k;
// k++;
// }
// }
/*输入方式二*/
// for (int i = 0; i < 4; ++i){
// for (int j = 0; j < 4; ++j){
// cin >> atlas[i][j];
// value <<= 1;
// if(atlas[i][j] == 'b') value += 1;
// }
// }
/*输入方式三*/
// for (int i = 0; i < 16; ++i)
// {
// char c;
// cin >> c;
// if(c == 'b') value += judge[i];
// }
解法一:暴力搜索
/**********************************
暴力搜索法
每个棋子要么翻要么不翻,总共有2^16 = 65536种可能性;
假设每一位用1表示翻棋,则可以用0-65535表示这65536种可能性;
遍历所有翻棋方法,找到使当前棋局变为全白或全黑的方法并保存步数;
找到其中最小步数。
**********************************/
#include <cstdio>
#include <iostream>
using namespace std;
char atlas[5][5];//1表示黑棋
int change[20] = {
0xc800,0xe400,0x7200,0x3100,
0x8c80,0x4e40,0x2720,0x1310,
0x08c8,0x04e4,0x0272,0x0131,
0x008c,0x004e,0x0027,0x0013
};
int judge[20] = {
0x8000,0x4000,0x2000,0x1000,
0x0800,0x0400,0x0200,0x0100,
0x0080,0x0040,0x0020,0x0010,
0x0008,0x0004,0x0002,0x0001
};
int value;
int step;
int main()
{
value = 0;
step = 17;
int k = 0;
for (int i = 0; i < 4; ++i){
for (int j = 0; j < 4; ++j){
cin >> atlas[i][j];
if(atlas[i][j] == 'b') value += 1<<k;
k++;
}
}
for (int i = 0; i < 65536; ++i) {//65536种翻棋方法
int tvalue = value;
int tstep = 0;
for (int j = 0; j < 16; ++j){//依次判断16个棋子是否翻动
if (i & judge[j]){
tvalue ^= change[j];
tstep++;
}
}
if (tvalue == 0 || tvalue == 65535) step = min(step,tstep);
}
if(step < 17) cout << step << endl;
else cout << "Impossible" << endl;
return 0;
}
解法二:宽度优先搜索
/**********************************
广度优先搜索
首先进行棋盘的状态压缩,保存棋盘;
然后对棋盘进行广度优先搜索;
要注意,广搜入口有16个,但是由于翻棋顺序对于棋盘结果不影响,所以翻棋状态只有2^16 = 65536种。
**********************************/
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
int change[20] = {//16个翻棋方式
0xc800,0xe400,0x7200,0x3100,
0x8c80,0x4e40,0x2720,0x1310,
0x08c8,0x04e4,0x0272,0x0131,
0x008c,0x004e,0x0027,0x0013
};
int value;
int step;
int visit[65536];
typedef pair<int,int> p;
queue <p> qu;
void bfs()
{
while(!qu.empty()){
p f = qu.front();qu.pop();
for (int i = 0; i < 16; ++i){
int tf = f.first^change[i];
int tstep = f.second + 1;
if(visit[tf]) continue;
if(tf == 0 || tf == 65535){
step = tstep;return;
}
visit[tf] = 1;
qu.push(make_pair(tf,tstep));
}
}
}
int main()
{
value = 0;
step = 17;
for (int i = 0; i < 4; ++i){
for (int j = 0; j < 4; ++j){
char c;
cin >> c;
value <<= 1;
if(c == 'b') value += 1;
}
}
if(value == 0 || value == 65535) {
cout << "0" << endl;return 0;
}
qu.push(make_pair(value,0));
memset(visit,0,sizeof(visit));
visit[value] = 1;
bfs();
if(step < 17) cout << step << endl;
else cout << "Impossible" << endl;
return 0;
}