题目大意:给定一张n*m的方格图,有白黑两种颜色,每次可以选取一个十字进行翻转,白变成黑,黑变成白,问最少需要翻转几次,如果有重复的,按字典序最小的进行输出;
题目解析:开关问题,这道题跟7276很相似,只不过从一维转化成了二维的,如果我们像之前的考虑第一个(1,1),那么(1,2)和(2,1)会对他造成影响,不是唯一解,所以我们可以考虑第一行,把第一行的所有情况都考虑一遍,那么从第二行开始枚举,如果(i-1,j)是黑色的话,那么(i,j)就必须翻转,这样就是唯一的了,最后只要在判断最后一排是否权威白色就可以了;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int n,m,graph[16][16];
int opt[16][16],temp[16][16];
int dx[5]={-1,0,0,0,1};
int dy[5]={0,1,0,-1,0};
int get(int x,int y)
{
int i,j,cnt=graph[x][y];
for(i=0;i<5;i++)
{
int x1=x+dx[i],y1=y+dy[i];
if(x1>=0&&x1<n&&y1>=0&&y1<m)
{
cnt+=temp[x1][y1];
}
}
return cnt%2;
}
int calu()
{
int i,j,cnt=0;
for(i=1;i<n;i++)
{
for(j=0;j<m;j++)
{
if(get(i-1,j)==1)
{
temp[i][j]=1;
}
}
}
for(i=0;i<m;i++)
{
if(get(n-1,i)==1)
return -1;
}
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
cnt+=temp[i][j];
}
return cnt;
}
void solve()
{
int i,j,ans=-1;
for(i=0;i<(1<<m);i++)
{
memset(temp,0,sizeof(temp));
for(j=0;j<m;j++)
{
temp[0][m-j-1]=(i>>j)&1;
}
int num=calu();
if(num!=-1&&(ans==-1||ans>num))
{
ans=num;
memcpy(opt,temp,sizeof(temp));
}
}
if(ans==-1)
printf("IMPOSSIBLE\n");
else
{
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
printf("%d%c",opt[i][j],j==m-1?'\n':' ');
}
}
}
}
int main()
{
int i;
while(scanf("%d%d",&n,&m)!=EOF)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
scanf("%d",&graph[i][j]);
solve();
}
return 0;
}