(枚舉+狀壓)POJ3279Fliptile

POJ3279Fliptile

題意&思路:

有一個m*n的01矩陣,每次選一個格子會翻轉這個格子和他的上下左右。問是否能將所有的格子變成0,能就輸出翻轉次數最小的方案(有多個即輸出字典序最小的),0表示不反轉,1表示翻轉。如果沒有輸出“IMPOSSIBLE"。
這是kuangbin的搜索題單裏的一道題,之前一直沒有思路。看了其他人的題解,其實就是枚舉狀態,然後可以發現如果(i-1,j)點的值是1,就通過翻轉(i,j)來改變。就這樣通過一層層的枚舉來保證上一行全是0,最後判斷最後一行是不是都爲0就可以了。

代碼:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<ctype.h>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#define pii pair<int,int>
#define ll long long
#define cl(x,y) memset(x,y,sizeof(x))
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
const int N=1e6+10;
const int mod=1e7+9;
const int maxn=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
const int inf=99999999;
using namespace std;
int maze[20][20],pre[20][20],ans[20][20],temp[20][20],dis[5][2]={{0,0},{1,0},{-1,0},{0,1},{0,-1}};
int n,m;
int step,res=maxn;
void change(int x,int y)
{
	int i;
	for(i=0;i<5;i++)
		temp[x+dis[i][0]][y+dis[i][1]]^=1;
	return;
}
int solve()
{
	int i,j;
	memcpy(temp,maze,sizeof(maze));
	for(i=1;i<=m;i++)
		if(pre[1][i])
		{
			change(1,i);
			step++;
		}
	for(i=2;i<=n;i++)
		for(j=1;j<=m;j++)
			if(temp[i-1][j])
			{
				pre[i][j]=1;
				change(i,j);
				step++;
			}
	for(i=1;i<=m;i++)
		if(temp[n][i])
			return 0;
	return 1;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			cin>>maze[i][j];
	for(i=0;i<(1<<m);i++)
	{
		cl(pre,0);
		step=0;
		for(j=0;j<m;j++)
			pre[1][m-j]=(i>>j)&1;
		if(solve() && step>0 && res>step)
		{
			res=step;
			memcpy(ans,pre,sizeof(pre));
		}
	}
	if(res==maxn)
		cout<<"IMPOSSIBLE"<<endl;
	else
	{
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
				cout<<ans[i][j]<<" ";
			cout<<endl;
		}
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章