POJ 3279Fliptile(搜索)

题目来源:http://poj.org/problem?id=3279

有一个m*n的棋盘,每个格子上是0或1,每次可以对一个格子做一次翻转操作,将翻动的格子和上下左右4个格子的0/1翻转。问最少做多少次翻转可以将所有格子翻转成0,输出翻转方案。没有方案时输出“IMPOSSIBLE”。

拿到题目还是没想到有效的解决办法,因为放在搜索里,所以往那靠。

先枚举第一行的所有状态(也就是翻转的状态)(并不是改变原来的第0行,而是改变第一行的book翻转,进行方便之后的判断),0~~1<<n,2的n次方的不同形式,然后往下走下面的行,直到m-1行,看看m行是不是都为0了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,m;
int s[20][20],book[20][20],per[20][20];
int move[5][2]={{0,0},{0,1},{0,-1},{-1,0},{1,0}};
int check(int x,int y)//判断周围的块翻动的次数导致的结果
{
	int temp=s[x][y];
	for(int i=0;i<5;i++)
	{
		int xx=x+move[i][0];
		int yy=y+move[i][1];
		if(xx<0||yy<0||xx>=m||yy>=n)
		continue;
		temp+=book[xx][yy];
	}
	return temp%2;//奇数则为1,偶数为0
}
int dfs()
{
	int i,j;
	for(i=1;i<m;i++)
	{
		for(j=0;j<n;j++)
		if(check(i-1,j))
		book[i][j]=1;
	}
	for(i=0;i<n;i++)
	if(check(m-1,i))
	return -1;
	int sum=0;
	for(i=0;i<m;i++)
	for(j=0;j<n;j++)
	sum+=book[i][j];
	return sum;
}
int main()
{
	int i,j;
	scanf("%d %d",&m,&n);
	memset(book,0,sizeof(book));
	for(i=0;i<m;i++)
	{
		for(j=0;j<n;j++)
		{
			scanf("%d",&s[i][j]);
		}
	}
	int flag=0,ans=0x3f3f3f3f;
	for(i=0;i<1<<n;i++)
	{
		memset(book,0,sizeof(book));
		for(j=0;j<n;j++)
		book[0][n-1-j]=i>>(j)&1;
		int hh=dfs();
		if(hh>=0&&hh<ans)
		{
			ans=hh;
			flag=1;
			memcpy(per,book,sizeof(book));
		}
	}
	if(!flag)
	printf("IMPOSSIBLE");
	else
	{
		for(i=0;i<m;i++)
		{
			for(j=0;j<n;j++)
			printf("%d ",per[i][j]);
			printf("\n");
		}
	}
	return 0;
} 
发布了56 篇原创文章 · 获赞 17 · 访问量 2348

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/98475910