解题报告:题目大意有一个N×N的矩阵,矩阵中的元素只有1或0,如果说对于一个矩阵,它的所有的点的上下左右的点的和是偶数,则称这个矩阵为偶数矩阵,现在给你一个任意的矩阵,要求的是如果要把这个矩阵变成偶数矩阵的话,最少需要将多少个点由1变成0,若不存在话,输出-1.(N<=15)
这题如果枚举每个点的情况的话,虽然N最大只有15,但这样枚举的计算量依然非常大。但是我们可以发现,如果知道第一行的每一个点是什么样的,完全可以计算出下面的N-1行的每一个点。这样我们只要枚举第一行的每一个点的情况,这样的话时间复杂度就降为2^15,很明显快多了。

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int xxx[5]={0,-1,0,1,0}; 6 int yyy[5]={0,0,1,0,-1}; 7 const int MAX=0xffffff; 8 int n,mep[16][16]; 9 int check(int s) { 10 int mp[16],map[16][16],tot=0; 11 memset(mp,0,sizeof(mp)); 12 memset(map,0,sizeof(map)); 13 for(int i=0;i<n;++i) 14 if(s & (1<<i)) { 15 if(mep[1][i+1]==0) 16 tot++; 17 mp[i+1]=1; 18 } 19 else if(mep[1][i+1]==1) 20 return MAX; 21 for(int i=1;i<=n;++i) 22 map[1][i]=mp[i]; 23 for(int i=2;i<=n;++i) 24 for(int j=1;j<=n;++j) 25 map[i][j]=mep[i][j]; 26 27 for(int i=1;i<=n;++i) 28 for(int j=1;j<=n;++j) { 29 int sum=0; 30 for(int k=1;k<=4;++k) { 31 int xx=i+xxx[k]; 32 int yy=j+yyy[k]; 33 if(xx<=0||yy<=0||xx>n||yy>n) 34 continue; 35 sum+=map[xx][yy]; 36 } 37 if(sum%2) { 38 if(i!=n&&map[i+1][j]==0) { 39 map[i+1][j]=1; 40 tot++; 41 } 42 else return MAX; 43 } 44 } 45 return tot; 46 } 47 48 int main( ) { 49 int T; 50 scanf("%d",&T); 51 for(int l=1;l<=T;++l) { 52 scanf("%d",&n); 53 for(int i=1;i<=n;++i) 54 for(int j=1;j<=n;++j) 55 scanf("%d",&mep[i][j]); 56 int ans=MAX; 57 for(int s = 0;s < (1 << n ) ; ++s) //(1 << n )注意这个范围不能大也不能小 58 ans=min(check(s),ans); 59 if(ans==MAX) 60 ans=-1; 61 printf("Case %d: %d ",l,ans); 62 } 63 return 0; 64 }