这个问将所给m*n的01矩阵,需要求出最少将0变成1的次数,使得所有点的上下左右之和为偶数。有题目的要求可以知道如果对整个地图用DFS的话会超时,而且超时会很严重,而通过观察可以发现后面的几行可以由第一行递推得出。
解法:
首先用DFS枚举第一行的所有情况,然后对每种情况进行递推后面的变化情况,然后取最小即可。
代码:
#include<cstdio> #include<cstring> #include<iostream> #define MAX 16 using namespace std; const int maxn=1<<16,inf=1<<28; int n,map[MAX][MAX],vis[maxn],step,ans; int movex[3]={0,-1,0},movey[4]={1,0,-1}; bool isborder(int x,int y) { if(x<0||x>=n||y<0||y>=n) return true; return false; } void Deal() { int anst=step; int imap[MAX][MAX]; memcpy(imap,map,sizeof(map)); for(int i=0;i<n-1;i++) for(int j=0;j<n;j++) { int sum=0; for(int k=0;k<3;k++) { int itx=i+movex[k]; int ity=j+movey[k]; if(isborder(itx,ity)) continue; sum+=imap[itx][ity]; } if(imap[i+1][j]) { sum++; if(sum&1) return; } else { if(sum&1) { imap[i+1][j]=1; anst++; } } } for(int j=0;j<n;j++) { int sum=0; for(int k=0;k<3;k++) { int itx=n-1+movex[k]; int ity=j+movey[k]; if(isborder(itx,ity)) continue; sum+=imap[itx][ity]; } if(sum&1) return; } ans=min(ans,anst); } void DFS(int deep) { if(deep==n) { Deal(); return ; } if(!map[0][deep]) { map[0][deep]=1; step++; DFS(deep+1); step--; map[0][deep]=0; } DFS(deep+1); } int main() { int T,cas=1; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&map[i][j]); step=0,ans=inf; DFS(0); if(ans==inf) printf("Case %d: -1\n",cas++); else printf("Case %d: %d\n",cas++,ans); } return 0; }