POJ3279 Fliptile 枚举+简单搜索
题意:一个矩阵,每个点1或0,然后每次翻一个点,它周围上下左右(包括自己)1-》0,0-》1,问最少翻几次可以矩阵全是0,忽略题目说的字典序
分析:枚举第一行所有的情况,然后下面几行也随之确定了,然后看哪种好就行,因为每行宽最多15 所有二进制枚举一下。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<map> #include<stdlib.h> #include<string> using namespace std; typedef long long LL; const int maxn=20; const int INF=0x3f3f3f3f; int o[maxn][maxn]; int now[maxn][maxn]; int temp[maxn][maxn]; int res[maxn][maxn]; int n,m,ans; int dx[4]= {0,0,-1,1}; int dy[4]= {-1,1,0,0}; void change(int x,int y) { now[x][y]=1-now[x][y]; for(int i=0; i<4; ++i) { int p=x+dx[i]; int q=y+dy[i]; if(p<1||p>n||q<1||q>m)continue; now[p][q]=1-now[p][q]; } } bool check(int x,int y) { if(now[x-1][y])return true; return false; } void solve(int x) { for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) now[i][j]=o[i][j]; int a[maxn],cnt=0,c=0,flag=0; memset(temp,0,sizeof(temp)); memset(a,0,sizeof(a)); while(x) { a[++cnt]=x%2; x>>=1; if(a[cnt])++c; } for(int i=1; i<=m; ++i) if(a[i])change(1,i),temp[1][i]++; for(int i=2; i<=n; ++i) for(int j=1; j<=m; ++j) if(check(i,j))++c,change(i,j),temp[i][j]++; for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) if(now[i][j])flag=1; if(!flag&&c<ans) { ans=c; for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) res[i][j]=temp[i][j]; } } int main() { while(~scanf("%d%d",&n,&m)) { for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) scanf("%d",&o[i][j]); ans=INF; int l=(1<<m); for(int i=0; i<l; ++i) solve(i); if(ans==INF) { printf("IMPOSSIBLE\n"); continue; } else { for(int i=1; i<=n; ++i) { for(int j=1; j<m; ++j) printf("%d ",res[i][j]); printf("%d\n",res[i][m]); } } } return 0; }