题目链接:POJ3279
思路很重要。
第一点,N最大只有15 ,考虑到第一排的翻转情况确定之后,整个棋盘的翻转情况也就确定了。最多遍历2^15种。
第二点,对于每一排的1,只有其下面的翻转能将其变为0,而不影响同行其他棋子的翻转情况。
第三点,坐标系的建立要统一,x,y,m,n, x指的是row 那么y指的是col ,都统一用一个坐标系不容易错。
这题目的思路值得借鉴,思考。不看他人的题解,我也想不到。
AC代码;
#include<stdio.h>
#include<string.h>
const int maxn=20;
bool mp[maxn][maxn],ans[maxn][maxn],f[maxn][maxn],tmp[maxn][maxn];
int m,n,res=300;
void flip(int x,int y){
tmp[x][y]=!tmp[x][y];
if(x-1>=0) tmp[x-1][y]=!tmp[x-1][y];
if(x+1<m) tmp[x+1][y]=!tmp[x+1][y];
if(y-1>=0) tmp[x][y-1]=!tmp[x][y-1];
if(y+1<n) tmp[x][y+1]=!tmp[x][y+1];
}
void print(bool t[maxn][maxn]){
// puts("");
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
printf("%d ",t[i][j]);
}puts("");
}
// puts("");
}
int main(){
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++){
for(int j=0;j<n;j++)
scanf("%d",&mp[i][j]);
}
/*
// check input
// memcpy(f,mp,sizeof(mp));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
printf("%d ",f[i][j]);
}puts("");
}
// */
for(int i=0;i<(1<<n);i++){
// memcpy(f,mp,sizeof(mp));
memset(f,false,sizeof(f));
//printf("%d:",i);
for(int j=0;j<n;j++){
f[0][n-j-1]=(i>>j)&1;
// printf("%d ",f[0][n-j-1]);
}
// for(int j=0;j<n;j++) printf("%d ",f[0][j]);puts("");
int fcnt=0;
memcpy(tmp,mp,sizeof(mp));
for(int j=0;j<n;j++){
if(f[0][j]){
flip(0,j);
fcnt++;
}
}
for(int j=0;j<m-1;j++){
for(int k=0;k<n;k++){
if(tmp[j][k]==1){
f[j+1][k]=1;
flip(j+1,k);
fcnt++;
// if(i==0) printf("%d,%d\n",j+1,k);
// if(i==0) print(tmp);
}
}
}
// printf("fcnt=%d\n",fcnt);
bool flag=true;
for(int j=0;j<n;j++){
if(tmp[m-1][j]) flag=false;
// printf("%d ",tmp[m-1][j]);
}
//puts("");
if(!flag) continue;
else{
if((fcnt<res)){
memcpy(ans,f,sizeof(f));
res=fcnt;
}
}
}
// printf("res:%d\n",res);
memcpy(tmp,mp,sizeof(mp));
if(res!=300) print(ans);
else printf("IMPOSSIBLE\n");
return 0;
}