POJ1753(BFS+位压缩)

题目大意:

一个4×4的棋盘上有16枚棋子。每枚棋子都有正反两面,给出棋盘上棋子的初始状态,求将棋盘上棋子全部翻转成正面或者反面的最小步数。翻转规则如下:

当翻转棋子a[i][j]:

a[i-1][j],a[i+1][j],a[i][j-1],a[i][j+1]

也会跟着翻动。根据棋子的不同位置,每翻转一枚棋子都会有2到4枚棋子跟着一起翻转。

棋盘的状态数为2^16。假设将棋子排成一排每种状态都可以用以下公式表示

2^1*x+2^2*x+...+2^16*x(x取0或者1)

按位异或:a^b,a与b不同为1,相同为0.

a^1 当a=1结果为0,a=0时结果1,实现翻转位。
a^0当a=0结果为0,a=1结果为1,保持不变。
假设棋盘当前状态为iCurState;当翻动第1至第16枚棋子时,用以下公式进行转换
pattern[16] = {0xc800,0xe400,0x7200,0x3100,0x8c80,0x4e40,0x2720,0x1310,
0x08c8,0x04e4,0x0272,0x0131,0x008c,0x004e,0x0027,0x0013 };
iCurState^patter[i]

看到这些东西很容易想到BFS,附上代码:

#include <iostream>
#include <cmath>
#include <queue>
using namespace std;

const unsigned short pattern[16] = {0xc800,0xe400,0x7200,0x3100,0x8c80,0x4e40,0x2720,0x1310,
0x08c8,0x04e4,0x0272,0x0131,0x008c,0x004e,0x0027,0x0013 };
queue<int> m_queue;
int input()
{
	int m_curstatue = 0;
	char ch;
	for (int i = 0 ;i < 4 ; i ++)
	{
		for (int j = 0 ; j < 4; j ++)
		{
			cin>>ch;
			if ('b' == ch)
			{
			    if(0 == i)
				   m_curstatue += pow(2.0,j);
			    else
				   m_curstatue += pow(2.0,i*4 +j);
			}

		}
	}
	return m_curstatue;
}
char mark[65536];
int bfs(int m_curstatue)
{

	memset(mark,-1,sizeof(mark));
	m_queue.push(m_curstatue);
	mark[m_curstatue] = 0;
	int statue = 0;
	while(!m_queue.empty()) 
	{

	    int tmp_front = m_queue.front();
	    m_queue.pop();
		if (tmp_front == 0 || tmp_front == 65535)
		{
			return 0;
		}
	    for (int i = 0 ;i < 16 ; i ++)
		{
		   int tmp = tmp_front ^ pattern[i];
		   if (mark[tmp] == -1)
		   {
		       m_queue.push(tmp);
			   mark[tmp] = mark[tmp_front] + 1;
		       statue ++;
		       if (tmp == 65535 || tmp == 0)
			   {
                             return mark[tmp];
			   }
	
		   }
		}
	}
	return -1;
}
int main()
{
	
    int m_curstatue = input();
	int ans = bfs(m_curstatue);
	if (-1 == ans)
		cout<<"Impossible"<<endl;
	else
		cout<<ans<<endl;
	return 0;
}

此题还可以用:高斯消元和枚举的方法,将在以后博文发出。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值