POJ 1753 Flip Game

题目:http://poj.org/problem?id=1753

题目的意思是:一个棋盘游戏,棋盘由4x4的方格组成,棋子有两种状态,一种是白色,一种是黑色。游戏的规则如下:

1.      棋子可以翻转,每次翻转,原来白色的状态变成黑色,原来黑色的状态变成白色。

2.      翻转任何一个棋子,它的4个相邻(上下左右)的棋子也同时翻转。

当棋盘上16个棋子都变成白色或者黑色,则游戏结束。

具体的输入输出要求可以查看题目,在此就不详细叙述了。

分析这个题目的基本思路如下:

从题目中可以获得以下几条信息:

1.      任何棋子最多翻转一次,翻转超过一次都是没有意义的。(可以证明。简单的说就是翻转两次相当于没有翻转)

2.      棋子只有16个,根据第一条信息每个棋子最多翻一次,那么所有棋子最多翻转16次。

3.      棋子翻转的顺序对最后的结果没有影响。

4.     每个棋子只有两个状态。

根据以上信息可以得到解题的基本思路。由于翻转棋的方案最多只有2^16种,用枚举的方式可以暴力求解。具体的方法可以采用深度优先搜索(DFS)或者广度优先搜索(BFS)。由于题目没有要求输出具体需要翻转哪些棋子,用BFS会比DFS更快的找到最短路径,如果需要输出路径,那么用DFS会更方便。

标示棋盘的数据结构可以采用4x4的二维数组,也可以用16bit来存储棋盘数据。使用bit位来存储数据不但可以节省空间,在进行翻转操作的时候,直接使用异或操作比较简便。

使用DFS方法的代码如下:

#include<stdio.h>
const int status[16]={0xC800 , 0xE400 , 0x7200 , 0x3100 ,
						  0x8C80 , 0x4E40 , 0x2720 , 0x1310 ,
						  0x08c8 , 0x04E4 , 0x0272 , 0x0131 ,
						  0x008c , 0x004E , 0x0027 , 0x0013};
int flipGame=0;
int result=17;
void read()
{
	int i; 
	char c;
	for(i=0;i<16;i++)
	{
		c=getchar();
		if(c=='b')
		{
			flipGame=flipGame<<1;
			flipGame^=1;
		}
		else if(c=='w')
		{
			flipGame=flipGame<<1;
		}
		else
		{
			i--;
		}
	}
}
void search(int step, int index)
{
	if(step>=result)
	{
		return;
	}
	if(index>=16)
	{
		if(flipGame==0xffff || flipGame==0x0000) 
		{
			if(result>step)
			{
				result=step;
			}
		}
		return;
	}
	search(step,index+1);     //不翻转,进入下一步
	flipGame^=status[index];
	search(step+1,index+1);   //翻转,进入下一步
	flipGame^=status[index];  //恢复原位 
	return;
}
int main(void)
{
	read();
	search(0,0);
	if (result >= 17)  
    {  
        printf("Impossible");  
    }  
    else  
        printf("%d",result); 
	printf("\n");
	return 1;
}
BFS要使用到队列,为了方便,使用了C++的标准库。BFS方法的代码如下:
#include<cstdio>
#include<queue>
using namespace std;
const int status[16]={0xC800 , 0xE400 , 0x7200 , 0x3100 ,
						  0x8C80 , 0x4E40 , 0x2720 , 0x1310 ,
						  0x08c8 , 0x04E4 , 0x0272 , 0x0131 ,
						  0x008c , 0x004E , 0x0027 , 0x0013};
int flipGame=0;
int result;
typedef struct Node
{
	int state;
	int step;
}flipNode;
void read()
{
	int i; 
	char c;
	for(i=0;i<16;i++)
	{
		c=getchar();
		if(c=='b')
		{
			flipGame=flipGame<<1;
			flipGame^=1;
		}
		else if(c=='w')
		{
			flipGame=flipGame<<1;
		}
		else
		{
			i--;
		}
	}
}
int bfs(int flipGame)
{
	int i;
	bool vis[65536];
	memset(vis , 0, sizeof(vis));
	queue<flipNode>node;
	flipNode front,next;
	front.state=flipGame;
	front.step=0;
	node.push(front);
	vis[flipGame]=true;
	while(!node.empty())
	{
		front=node.front();
		node.pop();
		if(front.state == 0 || front.state == 0xffff )
		{
			return front.step;
		}
		for(i=0;i<16;i++)
		{
			next.state=front.state^status[i];
			next.step=front.step+1;
			if(vis[next.state])  
                continue;  
            if(next.state == 0 || next.state == 0xffff)
                return next.step;  
            vis[next.state] = true;  
            node.push(next); 
		}
	}
	return -1;
}
int main(void)
{	
	read();
	result=bfs(flipGame);
	if (result ==-1)  
    {  
        printf("Impossible\n");  
    }  
    else  
        printf("%d\n",result); 
	printf("\n");
	return 0;
}
使用DFS方法输出翻转路径的代码如下:
#include<stdio.h>
const int status[16]={0xC800 , 0xE400 , 0x7200 , 0x3100 ,
						  0x8C80 , 0x4E40 , 0x2720 , 0x1310 ,
						  0x08c8 , 0x04E4 , 0x0272 , 0x0131 ,
						  0x008c , 0x004E , 0x0027 , 0x0013};
int flipGame=0;
int result=17;
int path=0; //记录路径
void read()
{
	int i; 
	char c;
	for(i=0;i<16;i++)
	{
		c=getchar();
		if(c=='b')
		{
			flipGame=flipGame<<1;
			flipGame^=1;
		}
		else if(c=='w')
		{
			flipGame=flipGame<<1;
		}
		else
		{
			i--;
		}
	}
}
void search(int step, int index, int p)
{
	if(step>=result)
	{
		return;
	}
	if(index>=16)
	{
		if(flipGame==0xffff || flipGame==0x0000)
		{
			if(result>step)
			{
				result=step;
				path=p;
			}
		}
		return;
	}
	p=p<<1;
	search(step,index+1,p);
	p=p>>1;
	flipGame^=status[index];
	p=p<<1;
	p^=1;
	search(step+1,index+1,p);
	flipGame^=status[index];  //恢复原位 
	p=p>>1;
	return;
}
int main(void)
{
	int t,i,j;
	read();
	search(0,0,0);
	if (result >= 17)  
    {  
        printf("Impossible\n");  
    }  
    else  
        printf("%d\n",result); 
	for(i=4;i>=1;i--)
		for(j=4;j>=1;j--)
		{
			t=path%2;
			path=path>>1;
			if(t)
			{
				printf("(%d,%d)",i,j);
			}
		}
	printf("\n");
	return 1;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值