poj1753(位运算(异或)+ bfs)

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

         题目大意:在一个4*4的矩阵中,由16快一面是黑色,一面是白色的圆盘组成,现在照如下操作:

           1.在16快圆盘中任选一块,

            2.翻转该块圆盘和它上下左右的圆盘

         问如何能在翻转次数最少的情况下将16快圆盘翻成全是白色或者黑色,输出最少的翻转次数,如果怎么都达不到目标,则输出“Impossible”。

             思路:第一道位运算(只要是异或来翻转圆盘)题目,总共16块圆盘,所以16个二进制位就可以了,‘1’代表白色,‘0’代表黑色,所以最终状态是:“1111 1111 1111 1111”或“0000 0000 0000 0000”即代表成功了。具体看代码,有相对详细的解释。

#include<stdio.h>
#include<math.h>
#include<string.h>
typedef struct {
	int zt;
	int flips;
} state;
state q[65536];//队列
int head=0,tail=-1;
int flip[16]={19,39,78,140,305,626,1252,2248,4880,10016,20032,35968,12544,29184,58368,51200};
/* 对应翻转:
			 10011 100111 1001110 10001100 
                             100110001 1001110010 10011100100 100011001000
			 1001100010000 10011100100000 100111001000000 1000110010000000
			 11000100000000 111001000000000 1110010000000000 1100100000000000

*/
int fliped[65536];//标记状态是否出现过,由于总共只有65535种状态
char map[4][4];
void enq(state s) //进队
{
	++tail;
         q[tail].zt=s.zt;
	q[tail].flips=s.flips;
	fliped[q[tail].zt] = 1;
}
void deq()//出队
{
   ++head;
}
state gethead()//取队首元素
{
	return q[head];
}
int isempty()//判空
{
	if(head>tail)
		return 1;
	else 
		return 0;
}
int bfs()
{
   int i;
   state temp,temp1;
   memset(fliped,0,sizeof(fliped));
   enq(q[0]);
   while(!isempty())
   {
       temp=gethead();
	   deq();
	   if(temp.zt==0 || temp.zt == 65535)//达到了目标状态
		   return temp.flips;
	   else
	   {
		   for(i=0;i<16;i++)
		   {
			   temp1.zt =temp.zt ^ flip[i];//位异或翻转圆盘
			   if(!fliped[temp1.zt])//该状态没有出现过,入队,对应的翻转次数加1
			   {
				   temp1.flips=temp.flips+1;
				   enq(temp1);
			   }
		   }
	   }

   }
   return -1;
}
int main()
{
	int i,j,minflip;
	int Inizt=0;
	for(i=0;i<4;i++)
		scanf("%s",map[i]);
         for(i=0;i<4;i++)//求出初始状态
		for(j=0;j<4;j++)
		{
			if(map[i][j] - 'w' == 0)
				Inizt+=(int)pow(2,(double)(i*4+j));
		}
	    q[0].zt=Inizt;
		q[0].flips=0;
		minflip=bfs();
		if(minflip == -1)
			printf("Impossible\n");
		else 
			printf("%d\n",minflip);
		return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值