这个问将所给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;
}