[kuangbin带你飞]专题一 简单搜索(未完待更......)

POJ 3279 Fliptile

题意:

给定一m*n的01矩阵,每翻动一个格子,它上下左右四个格子也会翻面(0变1,1变0),问最少翻动几次,得全0矩阵。如果最小操作数对应多种操作方案 ,输出字典序最小的方案。如果不能得全0矩阵,输出“IMPOSSIBLE”。

思路: 

枚举第一行的操作,然后根据每种操做后的第一行的状态,往下递推后面行的操作(每行的操作由前一行的状态决定),最后判断最后一行是不是全0。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=20;
int n,m;

bool a[N][N],b[N][N],vis[N][N],ans[N][N];

void flip(int x,int y){
	a[x][y]^=1,a[x-1][y]^=1,a[x+1][y]^=1,a[x][y-1]^=1,a[x][y+1]^=1;
}

bool check(){
	for(int j=1;j<=n;++j){
		if(a[m][j]) return false;
	}
	return true;
}

int main(){	
    cin>>m>>n;//m行n列
	for(int i=1;i<=m;++i){
		for(int j=1;j<=n;++j){
			cin>>a[i][j];
		}
	}

	int op=1<<n;//枚举第一行的操作(后续操作就已被递推决定)
	int minn=n*m+1;
	bool flag=0;

	for(int i=0;i<op;++i){

		int cnt=0;
		memcpy(b,a,sizeof a);

		for(int j=0;j<n;++j){ //操作第一行
			if(i>>j&1){
				flip(1,j+1);//啊我傻缺了!做题专心点好吗。。。= =
				vis[1][j+1]=1;
				++cnt;
			}
		}

		//由第一行状态,递推完成剩下的操作
		for(int k=2;k<=m;++k){ //啊第m行也是要操作的 我好蠢。
			for(int j=1;j<=n;++j){
				if(a[k-1][j]){
					flip(k,j);
					vis[k][j]=1;
					++cnt;
				}
			}
		}
		
		//判断最后一行状态
		if(check()){
			flag=1;
			if(cnt<minn) {
				minn=cnt;
				memcpy(ans,vis,sizeof vis);
			}else if(cnt==minn){
				bool f=1;
				for(int i=1;i<=m&&f;++i){
					for(int j=1;j<=n&&f;++j){
						if(vis[i][j]<ans[i][j]){
							memcpy(ans,vis,sizeof vis);
							f=0;
						}else if(vis[i][j]>a[i][j]) f=0;
					}
				}
			}

		}

		memcpy(a,b,sizeof b);
		memset(vis,0,sizeof vis);
	}

	if(flag){
		for(int i=1;i<=m;++i){
			for(int j=1;j<=n;++j){
				if(j!=1) cout<<" ";
				cout<<ans[i][j];
			}
			puts("");
		}
	}else puts("IMPOSSIBLE");

	return 0;
}

PS:同类型题目

费解的开关(递推)

翻硬币(递推)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值