[BZOJ1054/Luogu4289][HAOI2008]移动玩具

题目链接:

BZOJ1054

Luogu4289

日常水题

因为总共(16)个节点,用二进制表示每一个状态,跑一遍最短路即可。

因为边权都是(1),直接(BFS)即可。

时间复杂度 (O(2^{16}*16*4)=AC)

#include <queue>
#include <cstdio>
#include <cstring>

int St,Ed,Dis[1<<16];
char s[5];

void BFS()
{
	if(St==Ed)return;
	std::queue<int> q;
	memset(Dis,0x3f,sizeof Dis);
	q.push(St),Dis[St]=0;
	for(int x;!q.empty();)
	{
		x=q.front(),q.pop();
		for(int i=0;i<16;++i)
		{
			int wx;
			if(i<12&&(x>>i&1)!=(x>>(i+4)&1))//不是第一行,且状态与上方不同
			{
				wx=x^(1<<i)^(1<<(i+4));//交换两位
				if(Dis[wx]>Dis[x]+1)
				{
					Dis[wx]=Dis[x]+1;
					if(wx==Ed)return;
					q.push(wx);
				}
			}//向上
			if(i>3&&(x>>i&1)!=(x>>(i-4)&1))
			{
				wx=x^(1<<i)^(1<<(i-4));
				if(Dis[wx]>Dis[x]+1)
				{
					Dis[wx]=Dis[x]+1;
					if(wx==Ed)return;
					q.push(wx);
				}
			}//向下
			if(i%4!=3&&(x>>i&1)!=(x>>(i+1)&1))
			{
				wx=x^(1<<i)^(1<<(i+1));
				if(Dis[wx]>Dis[x]+1)
				{
					Dis[wx]=Dis[x]+1;
					if(wx==Ed)return;
					q.push(wx);
				}
			}//向左
			if(i%4&&(x>>i&1)!=(x>>(i-1)&1))
			{
				wx=x^(1<<i)^(1<<(i-1));
				if(Dis[wx]>Dis[x]+1)
				{
					Dis[wx]=Dis[x]+1;
					if(wx==Ed)return;
					q.push(wx);
				}
			}//向右
		}
	}
}

int main()
{
	for(int i=0;i<4;++i)
	{
		scanf("%s",s);
		for(int j=0;j<4;++j)
			St=St<<1|(s[j]&1);
	}
	for(int i=0;i<4;++i)
	{
		scanf("%s",s);
		for(int j=0;j<4;++j)
			Ed=Ed<<1|(s[j]&1);
	}
	BFS();
	printf("%d
",Dis[Ed]);
	return 0;
}
原文地址:https://www.cnblogs.com/LanrTabe/p/10165667.html