[BZOJ1054/Luogu4289][HAOI2008]移动玩具
题目链接:
日常水题
因为总共\(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\n",Dis[Ed]);
return 0;
}