Uva-11464-Even Parity

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


你可能感兴趣的:(模拟,DFS)