bzoj 1647: [Usaco2007 Open]Fliptile 翻格子游戏【dfs】

这个可以用异或高斯消元,但是我不会呀我用的暴搜
2的m次方枚举第一行的翻转情况,然后后面的就定了,因为对于一个j位置,如果i-1的j位置需要翻,那么一定要翻i的j,因为这是i-1的j最后翻的机会
按字典序搜索然后取次数min即可

#include<cmath>  
#include<cstdio>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
using namespace std;  
const int N=20,inf=1707185547;  
int n,m,f[N][N],ans[N][N],p[N][N],a[N][N],mn=inf;  
void dfs(int x)  
{  
    if(x>m)  
    {  
        for(int i=1;i<=n;i++)  
			for(int j=1;j<=m;j++)  
				p[i][j]=a[i][j];  
        for(int i=1;i<=m;i++)  
			if(f[1][i])  
			{  
				p[1][i]^=1,p[2][i]^=1;  
				p[1][i+1]^=1,p[1][i-1]^=1;  
			}  
        for(int i=2;i<=n;i++)  
			for(int j=1;j<=m;j++)  
				{  
					if(p[i-1][j]==1)  
					{  
						f[i][j]=1;  
						p[i][j]^=1;  
						p[i][j+1]^=1,p[i][j-1]^=1;  
						p[i+1][j]^=1,p[i-1][j]^=1;  
					}  
					else 
						f[i][j]=0;  
					if(p[i-1][j]) 
						return;  
				}  
        bool flag=false;  
        for(int i=1;i<=n;i++)  
			for(int j=1;j<=m;j++)  
				if(p[i][j])  
				{  
					flag=true;  
					break;  
				}  
        if(!flag)  
        {  
            int tot=0;  
            for(int i=1;i<=n;i++)  
				for(int j=1;j<=m;j++)  
					if(f[i][j]) 
						tot++;  
            if(tot>=mn) 
				return;  
            mn=tot;  
            for(int i=1;i<=n;i++)  
				for(int j=1;j<=m;j++)  
					ans[i][j]=f[i][j];  
        }  
        return;  
    }  
    for(int i=0;i<=1;i++)  
    {  
        f[1][x]=i;  
        dfs(x+1);  
    }  
}  
int main()  
{  
    scanf("%d%d",&n,&m);  
    for(int i=1;i<=n;i++)  
		for(int j=1;j<=m;j++)  
			scanf("%d",&a[i][j]);  
    dfs(1);  
    if(mn==inf) 
		printf("IMPOSSIBLE");  
    else  
    {  
        for(int i=1;i<=n;i++)  
        {  
            for(int j=1;j<m;j++)  
            printf("%d ",ans[i][j]);  
            printf("%d\n",ans[i][m]);  
        }  
    }  
	return 0;
}  
posted @ 2018-05-26 22:29  lokiii  阅读(146)  评论(0编辑  收藏  举报