POJ 3279 Fliptile
爆搜。
一个一个位置搜下去。第一列的格子可以反转也可以不反转,之后的每一列,看他左边的那一个格是1还是0,如果是1,这一格必须反转,否则必须不反转。这是一个很强的剪枝。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; const int maxn=20; int n,m; int a[maxn][maxn]; int flag[maxn][maxn]; int ans[maxn][maxn]; int cnt,sum; int dir[4][2]= { {1,0}, {-1,0}, {0,1}, {0,-1}, }; void c() { for(int i=0; i<n; i++) for(int j=0; j<m; j++) ans[i][j]=flag[i][j]; } bool P(int a,int b) { if(a>=0&&a<n&&b>=0&&b<m) return 1; return 0; } void dfs(int id,int tot,int re) { int tmp=re; if(tot>=cnt) return; if(re==0) { c(); cnt=min(cnt,tot); return ; } if(id==n*m) return; int x=id%n,y=id/n; if(y==0||a[x][y-1]==1) { flag[x][y]=1; a[x][y]=(a[x][y]^1); if(a[x][y]==1) tmp++; else tmp--; for(int i=0; i<4; i++) { int nx=x+dir[i][0],ny=y+dir[i][1]; if(P(nx,ny)) { a[nx][ny]=(a[nx][ny]^1); if(a[nx][ny]==1) tmp++; else tmp--; } } dfs(id+1,tot+1,tmp); flag[x][y]=0; a[x][y]=(a[x][y]^1); for(int i=0; i<4; i++) { int nx=x+dir[i][0],ny=y+dir[i][1]; if(P(nx,ny)) a[nx][ny]=(a[nx][ny]^1); } } if(y==0||a[x][y-1]==0) dfs(id+1,tot,re); } int main() { while(~scanf("%d%d",&n,&m)) { sum=0; for(int i=0; i<n; i++) for(int j=0; j<m; j++) { scanf("%d",&a[i][j]); if(a[i][j]==1) sum++; } cnt=0x7fffffff; dfs(0,0,sum); if(cnt==0x7fffffff) printf("IMPOSSIBLE\n"); else { for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { printf("%d",ans[i][j]); if(j<m-1) printf(" "); else printf("\n"); } } } } return 0; }