题意
给定一张n*m的方格图,有1,0两种数字,每次可以选取一个十字进行翻转,1变成0,0变成1,问最少需要翻转几次,使它全部变成0,全部如果有重复的,按字典序最小的进行输出;
输入
第一行n,m
下面一个矩阵,代表方格图
输出
按矩阵原格式输出是否需要翻转
Sample Input
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
Sample Output
0 0 0 0
1 0 0 1
1 0 0 1
0 0 0 0
分析
这道题也是一个开关问题,但是相对于上一题(我博客的上一题[POJ3276]),显然这是个二维的矩阵了,调整一个会对四面八方有影响,这样就不能确定地做一件操作的。我们要想着如何变成一个有固定操作规律的方法。看数据也许能启发我们,因为N只有15,可能跟搜索有关。我们有以往的例子,在列用dfs枚举,在行就可以直接操作/DP。针对这个题,发现如果第一行确定了,第一行的某个值确定了,就只有它正下方的数字影响它,这样就可以确定下一行的翻转情况。以此类推,检验最后一行即可。
代码
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<cmath> 6 #include<cstdio> 7 #include<cstring> 8 #include<iostream> 9 #include<algorithm> 10 #define RG register int 11 #define rep(i,a,b) for(RG i=a;i<=b;++i) 12 #define per(i,a,b) for(RG i=a;i>=b;--i) 13 #define ll long long 14 #define inf (1<<29) 15 #define maxn 20 16 using namespace std; 17 int n,m,ans=inf; 18 int num[maxn][maxn],gra[maxn][maxn],tag[maxn][maxn],rec[maxn],an[maxn][maxn]; 19 inline int read() 20 { 21 int x=0,f=1;char c=getchar(); 22 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 23 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 24 return x*f; 25 } 26 27 inline void modify(int i,int j){gra[i][j]^=1,gra[i-1][j]^=1,gra[i][j-1]^=1,gra[i+1][j]^=1,gra[i][j+1]^=1;} 28 int p; 29 void judge() 30 { 31 memset(tag,0,sizeof(tag)); 32 rep(i,1,n)rep(j,1,m) gra[i][j]=num[i][j]; 33 rep(i,1,m) if(rec[i]) tag[1][i]=1,modify(1,i); 34 rep(i,2,n) 35 rep(j,1,m) 36 if(gra[i-1][j]) 37 modify(i,j),tag[i][j]=1; 38 rep(j,1,m) if(gra[n][j]) return; 39 int sum=0; 40 rep(i,1,n)rep(j,1,m) sum+=tag[i][j]; 41 if(sum<=ans) 42 { 43 ans=sum; 44 rep(i,1,n)rep(j,1,m) an[i][j]=tag[i][j]; 45 } 46 } 47 48 void dfs(int step) 49 { 50 if(step>m){judge();return;} 51 rec[step]=1;dfs(step+1); 52 rec[step]=0;dfs(step+1); 53 } 54 55 int main() 56 { 57 n=read(),m=read(); 58 rep(i,1,n)rep(j,1,m) num[i][j]=read(); 59 dfs(1); 60 if(ans==inf)puts("IMPOSSIBLE"); 61 else {rep(i,1,n){rep(j,1,m) printf("%d ",an[i][j]);puts("");}} 62 return 0; 63 }