Fliptile(简单搜索+枚举最小字典序)poj3279

题意概要:给出一个0,1矩阵,按压一下就会该点的数^1(也就是会翻转)求所有翻成0时最小的翻转次数,如果翻转次数相同,输出最小字典序。

题解:枚举第一行,因为下面一行只受到上一行的影响,也就是上一行的1只能通过下一行来翻成0,枚举时从小到大枚举;

代码

#include<string>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long 
#define up(i,a,n) for(int i=a;i<=n;i++)
int mp[20][20];
int mp1[20][20];
int chose[20][20];
int press[20][20];
int n,m;
int move1[5][2]={0,0,1,0,-1,0,0,1,0,-1};\\翻转的四个方向,因为我从1开始记录,旁边不影响,所以不考虑边界
bool judge();
int solve()
{
	int ans=0;
	up(i,1,m)
	{
		if(press[1][i]==1)//枚举的第一行
		{
			up(j,0,4)
			{
				mp[1+move1[j][0]][i+move1[j][1]]^=1;
				ans++;
			}
		}
	}
	up(i,2,n)
	{
		up(j,1,m)
		{
			if(mp[i-1][j]==1)//上一行的1只能由下一行解决
			{   up(k,0,4)mp[i+move1[k][0]][j+move1[k][1]]^=1;
				press[i][j]=1;
				ans++;
			}
		}
	}
	if(judge())
	{
		return ans;
	}
	return -1;
}
bool judge()
{
	up(i,1,m)
	{
		if(mp[n][i]==1)return false;
	}
	return true;
}
int main()
{
	scanf("%d %d",&n,&m);
	up(i,1,n)
	up(j,1,m)
	scanf("%d",&mp1[i][j]);
	int Min=99999999;
	int goal[20][20];
	for(int i=0;i<(1<<n);i++)
	{
		memset(chose,0,sizeof(chose));
		memcpy(mp,mp1,sizeof(mp1));
		memset(press,0,sizeof(press));
		up(j,1,n){
		chose[1][j]=(i>>(j-1))&1;//这里枚举第一行的翻转
		press[1][j]=chose[1][j];
	    }
	    int MMin=solve();
	    if(MMin==-1)
	    {
	    	continue;
		}
	    if(MMin<Min)
	    {
	    	memcpy(goal,press,sizeof(press));//交换答案
	    	Min=MMin;
		}
	}
	if(Min==99999999)
	{
		printf("IMPOSSIBLE\n");//没有办法翻转
	}
	else
	{
		up(i,1,n)
		{
			up(j,1,m)
			{
				printf("%d ",goal[i][j]);//输出答案
			}
			printf("\n");
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值