题目链接:https://vjudge.net/problem/UVA-11464
一道比较好的题目。
思路如下:
如果我们枚举每一个数字“变”还是“不变”,那么需要枚举$2^{255}$种情况,很显然不行。
那么我们就来优化一下:我们只枚举第一行的数,然后根据计算得出第二、三....行的数。
这样复杂度就优化到了$O(2^n imes n^2)$。
然后用$A[][]$和$B[][]$分别表示变化前后的矩阵。
那么现在的问题就简化成了如何枚举第一行和如何递推。
枚举第一行:运用了状压的思想,把一行数看成一个二进制数,然后$&(1<<c)$,看是否为1,由此我们就构造了一个如下图所示的矩阵。
递推方法:
求出$B[r-1][c]$的上、左、右数之和,如果为偶数,则$B[r][c]=0$,反之$B[r][c]=1$。
在递推中如果发现由$1$转变到$0$的情况,那么是不可能的。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 5 using namespace std; 6 7 const int maxn=15; 8 const int INF=0x7f7f7f; 9 int n,A[maxn][maxn],B[maxn][maxn]; 10 11 int check(int s){ 12 memset(B,0,sizeof(B)); 13 for(int c=0;c<n;c++){ 14 if(s&(1<<c)) B[0][c]=1; 15 else if(A[0][c]==1) return INF; 16 } 17 for(int r=1;r<n;r++){ 18 for(int c=0;c<n;c++){ 19 int sum=0; 20 if(r>1) sum+=B[r-2][c]; 21 if(c>0) sum+=B[r-1][c-1]; 22 if(c<n-1) sum+=B[r-1][c+1]; 23 B[r][c]=sum%2; 24 if(A[r][c]==1&&B[r][c]==0) return INF; 25 } 26 } 27 int cnt=0; 28 for(int r=0;r<n;r++) 29 for(int c=0;c<n;c++) if(A[r][c]!=B[r][c]) cnt++; 30 return cnt; 31 } 32 33 int main(){ 34 int T; 35 scanf("%d",&T); 36 for(int k=1;k<=T;k++){ 37 scanf("%d",&n); 38 for(int r=0;r<n;r++) 39 for(int c=0;c<n;c++) scanf("%d",&A[r][c]); 40 int ans=INF; 41 for(int s=0;s<(1<<n);s++) 42 ans=min(ans,check(s)); 43 if(ans==INF) ans=-1; 44 printf("Case %d: %d ",k,ans); 45 } 46 return 0; 47 }