问题
分析
枚举法,因为枚举全部的格子不现实,数量太多了,如果只枚举第一行,那么可以根据第一行推出第二行的情况,所以是可行的,时间复杂度 O ( n 2 ∗ 2 n ) O(n^2*2^n) O(n2∗2n)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn=15;
int mat[maxn][maxn],nmat[maxn][maxn],kase=0,T,n;
int main(void){
scanf("%d",&T);
while(kase<T) {
scanf("%d",&n);
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
scanf("%d",&mat[i][j]);
}
}
int s=(1<<n),ans=10000;
for(int i=0;i<s;++i){
memset(nmat,0,sizeof(nmat));
int flag=true;
for(int j=0;j<n;++j) {
nmat[0][j]=(i&(1<<j))?1:0;
if(nmat[0][j]==0 && mat[0][j]==1){
flag=false;
break;
}
}
if(!flag) continue;
for(int k=1;k<n;++k){
for(int j=0;j<n;++j){
//计算nmat[k-1][j]的上面,左右三个的和
int tot=0;
if(k>1) tot+=nmat[k-2][j];
if(j>0) tot+=nmat[k-1][j-1];
if(j<n-1) tot+=nmat[k-1][j+1];
nmat[k][j]=(tot&1)?1:0;
}
}
int t=0;
for(int k=0;k<n;++k){
for(int j=0;j<n;++j){
if(nmat[k][j]-mat[k][j]==1) ++t;
else if(nmat[k][j]-mat[k][j]==-1){
flag=false;
break;
}
}
if(!flag) break;
}
if(flag) ans=min(ans,t);
}
printf("Case %d: %d\n",++kase,(ans==10000)?-1:ans);
}
return 0;
}