大意:给出一个只用0,1表示的n*n的图,通过将0改变成1,使得最终的图中每一个数字周围(上,下,左,右)1的个数是偶数个。问最少改变的步数。
思路:可以枚举第一行的状态,进而求出第二行,第三行,这里需要判断的有两个地方就是你转变之后的位置,原始状态是不是1,是1就不需要改变,第二个就是原始状态是1,但终态是0,这是题中不允许出现的情况。每一格与原始状态不同的就可以加1。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int mp[20][20],cmp[20][20];
const int inf = 0x3f3f3f3f;
int n;
int check(int s)
{
memset(cmp, 0, sizeof(cmp));
for(int i = 0; i< n; i++)
{
if(s & (1<<i))
cmp[0][i] = 1;
else if(mp[0][i] == 1)
return inf;
}
for(int r=1; r< n; r++)
{
for(int c = 0; c< n; c++)
{
int sum = 0;
if(r > 1)
sum += cmp[r-2][c];
if(c > 0)
sum += cmp[r-1][c-1];
if(c < n-1)
sum += cmp[r-1][c+1];
cmp[r][c] = sum % 2;
if(mp[r][c] == 1 && cmp[r][c] == 0)
return inf;
}
}
int cnt = 0;
for(int i = 0; i< n; i++)
{
for(int j = 0; j< n; j++)
{
if(mp[i][j] != cmp[i][j])
cnt++;
}
}
return cnt;
}
int main()
{
int t;
scanf("%d", &t);
for(int kcase = 1; kcase<= t; kcase++)
{
scanf("%d", &n);
for(int i = 0; i< n; i++)
{
for(int j = 0; j< n; j++)
{
scanf("%d", &mp[i][j]);
}
}
int ans = inf;
for(int i = 0; i< (1<<n); i++)
{
ans = min(ans, check(i));
}
if(ans == inf)
ans = -1;
printf("Case %d: %d\n", kcase, ans);
}
return 0;
}