算法流程

  1. 枚举第一行的修改情况 change[0]
  2. 每一行修改后的结果,即为该行的输入input[i]change[i]change[i >> 1]change[i << 1] & ((1 << M) - 1)^异或运算结果,这里注意,在进行change[i << 1]左移运算时,要跟(1 << M) - 1进行&运算的原因是,只保留后M位的运算结果,其他全部需要清零,以避免影响最终结果。
  3. 每一行的修改情况,即为上一行在修改后留下的结果,change[i] = cur[i - 1],因为只有当前行可以将上一行为1的位进行翻转。
  4. 最后判断是否已经达到全0(只需判断最后一行即可,因为此时cur[1]~cur[N-1]全为0)。

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 4, M = 4;
int a[N + 10], b[N + 10];
int change[N + 10];

int calc(int x)
{
	int cnt = 0;
	while (x)
	{
		if (x & 1)
			cnt++;
		x >>= 1;
	}
	return cnt;
}

int deal(int a[])
{
	int cur[N + 10], cnt = 0, ans = 0x7f7f7f7f;
	for (change[0] = 0; change[0] <= (1 << M) - 1; change[0]++)
	{
		cnt = calc(change[0]);
		cur[0] = a[0] ^ change[0] ^ (change[0] >> 1) ^ ((change[0] << 1) & ((1 << M) - 1));
		cur[1] = a[1] ^ change[0];
		for (int i = 1; i < N; i++)
		{
			change[i] = cur[i - 1];
			cnt += calc(change[i]);
			cur[i] = cur[i] ^ change[i] ^ (change[i] >> 1) ^ ((change[i] << 1) & ((1 << M) - 1));
			cur[i + 1] = a[i + 1] ^ change[i];
		}
		if (cur[N - 1] == 0)
		{
			ans = min(ans, cnt);
		}
	}
	return ans;
}

int main()
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
		{
			char c;
			scanf(" %c", &c);
			if (c == 'b')
				a[i] |= (1 << j);
			else
				b[i] |= (1 << j);
		}

	int ans = min(deal(a), deal(b));
	if (ans > N * M)
		cout << "Impossible";
	else
		cout << ans;

	return 0;
}