题意:给出一个4x4的棋盘状态,求用最少的次数,将棋盘中的棋子
翻成全部白色或黑色(如果要翻动其中一枚棋子,那它的上下左右的
棋子也要翻过来);最初还读错题,以为是全部翻成黑色。。。
囧啊。。读题真的是太不仔细了。。
由于一枚棋子最多只能翻一次,所以可以使用回溯,也可以用二进制状态压缩枚举,
枚举(0~(1<<16)-1)这个范围,1代表对该位置进行翻转,翻的次数就是该数二进制中1的个数了。
#include<stdio.h>
#define INF 0xffffff
int dp[5][5],vis[5][5];
int res;
int judge()
{
int f1=0,f2=0;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
{
if(!dp[i][j])
f1++;
else
f2++;
}
if(f1==16||f2==16)
return 1;
return 0;
}
void flip(int i,int j)/**位运算翻硬币*/
{
dp[i-1][j]^=1,dp[i][j-1]^=1,dp[i][j]^=1,dp[i][j+1]^=1,dp[i+1][j]^=1;
}
void dfs(int cur,int len,int i,int j)
{
if(cur>16||i>4||res<=cur)
return ;
if(len==cur)
{
if(judge())
res=res>cur?cur:res;
return ;
}
if(!vis[i][j]&&len<cur&&j<=4)
{
vis[i][j]=1;
flip(i,j);
dfs(cur,len+1,i,j+1);
vis[i][j]=0;
flip(i,j);
}
if(j<=4)
dfs(cur,len,i,j+1);
else
dfs(cur,len,i+1,1);
}
int main()
{
char c;
int i,j;
res=INF;
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
{
scanf("\n%c",&c);
if(c=='b')
dp[i][j]=1;
else
dp[i][j]=0;
}
for(i=0;i<=16;i++)
dfs(i,0,1,1);
if(res!=INF)
printf("%d\n",res);
else
printf("Impossible\n");
return 0;
}
#include <bitset>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
void flip(int s[4][4], int pos) {
int r = pos / 4, c = pos % 4;
s[r][c] ^= 1;
if(r - 1 >= 0) s[r - 1][c] ^= 1;
if(c - 1 >= 0) s[r][c - 1] ^= 1;
if(r + 1 < 4) s[r + 1][c] ^= 1;
if(c + 1 < 4) s[r][c + 1] ^= 1;
}
bool check(int a, int s[4][4]) {
int index = 0, w = 0, b = 0, t[4][4];
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
t[i][j] = s[i][j];
while(a) {
if(a & 1) flip(t, index);
a >>= 1, index++;
}
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
t[i][j] ? w++ : b++;
if(w == 16 || b == 16) return true;
return false;
}
int main() {
int s[4][4] = {0}, ans = 16;
char ch;
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++) {
cin >> ch;
if(ch == 'w') s[i][j] = 1;
}
for(int i = 0; i < (1 << 16); i++)
if(check(i, s)) {
bitset<16> b(i);
ans = min(ans, (int)b.count());
}
if(ans == 16) cout << "Impossible" << endl;
else cout << ans << endl;
return 0;
}