poj1753(dfs暴力枚举)

题意:有4*4的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑->白或者白->黑)时,其周围上下左右(如果存在的话)的格子的颜色也被反转,问至少反转几次可以使4*4的正方形变为纯白或者纯黑?

思路:

做这道题,首先要自己试试几个例子,然后提炼2个要点:

1.对同一个格子翻2次和翻0次的效果是一样的,同理翻3次和翻0次的效果也是一样的

2.对于2个格子,他们翻的顺序不影响结果

3.翻几次 对应于 对几个格子进行翻的操作

所以这题的问题就变成了“十六个格子里选几个格子进行翻转操作可以变成同色棋盘”,要么16选1,要么16选2,一直判断到16选16,总的情况为

看样子不会超时,所以放心大胆地用暴力枚举(dfs)吧,记得从16选0开始判断,依次增到16选16,如果都不满足说明不可能。

#include<iostream>
#include<string>    
using namespace std;

int map[6][6],ans,k,limt;

struct A
{
	int x,y;
};
A a[16];

void fan(int x,int y)           //翻转函数
{
	map[x][y]=!map[x][y];
	map[x-1][y]=!map[x-1][y];
	map[x+1][y]=!map[x+1][y];
	map[x][y+1]=!map[x][y+1];
	map[x][y-1]=!map[x][y-1];
}

int jude()                      //判断是否整个棋盘均为同一种颜色的函数
{
	int n1,n2,i,j;
	int t=map[1][1];                  //如果和map[1][1]不相等就返回0,否则返回1
	for(i=1;i<=4;i++)
		for(j=1;j<=4;j++)
			if(map[i][j]!=t)
				return 0;
	return 1;
	

}

void dfs(int cur,int d)                       //cur指当前你转了几个棋子,d指你这次该从哪个棋子开始选
{

	if(jude()) {ans=cur;}                         //如果棋盘达到条件,给ans赋值
	if(15-d<limt-cur-1||cur+1>limt) return ;      //如果剩余的可选棋子比所需棋子少或者你已经转的棋子比上限大
	for(int i=d;i<16&&ans==-1;i++)                  //从d开始选择该转的棋子。如果答案ans已经得到则退出循环
	{
		fan(a[i].x,a[i].y);                       //翻转棋子
		dfs(cur+1,i+1);                          //cur+1,同时i+1,即下一次应该从i+1的棋子开始选,避免重复
		fan(a[i].x,a[i].y);                       //记得翻回来
	}
}

int main()
{
	char str;
	int i,j;
	memset(map,0,sizeof(map));                 
	for(i=1;i<=4;i++)                           //构建棋盘
	{	
		for(j=1;j<=4;j++)
		{
			scanf("%c",&str);
			if(str=='b') map[i][j]=1;
			else map[i][j]=0;
		}
		getchar();
	}
	k=0;
	for(i=1;i<=4;i++)                         //用a数组放入每个棋子的坐标
	{
		for(j=1;j<=4;j++)
		{
			a[k].x=i;
			a[k++].y=j;
		}
	}
	ans=-1;                                 
	for(i=0;i<=16;i++)               
	{
		limt=i;                  //limt指上限,即你这次打算翻几个棋子
		dfs(0,0);
		if(ans!=-1)
		{
			printf("%d\n",ans);
			return 0;
		}
	}
	printf("Impossible\n");

}


 

POJ1753题目为"Flip Game",题目给出了一个4x4的棋盘,每个格子黑色白色,每次翻转一个格子会同时翻转它上下左右四个格子颜色,目标是把整个棋盘都变为同一种颜色,求把棋盘变成同种颜色的最小步数。 解题思路: 一般关于棋盘变色的题目,可以考虑使用搜索来解决。对于POJ1753题目,可以使用广度优先搜索(BFS)来解决。 首先,对于每个格子,定义一个状态,0表示当前格子白色,1表示当前格子黑色。 然后,我们可以把棋盘抽象成一个长度为16的二进制数,将所有格子的状态按照从左往右,从上往下的顺序排列,就可以用一个16位的二进制数表示整个棋盘的状态。例如,一个棋盘状态为: 0101 1010 0101 1010 则按照从左往右,从上往下的顺序把所有格子的状态连接起来,即可得到该棋盘的状态为"0101101001011010"。 接着,我们可以使用队列来实现广度优先搜索。首先将初始状态加入队列中,然后对于队列中的每一个状态,我们都尝试将棋盘上的每个格子翻转一次,生成一个新状态,将新状态加入队列中。对于每一个新状态,我们也需要记录它是从哪个状态翻转得到的,以便在得到最终状态时能够输出路径。 在搜索过程中,我们需要维护每个状态离初始状态的步数,即将该状态转换为最终状态需要的最小步数。如果我们找到了最终状态,就可以输出答案,即最小步数。 代码实现:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值