#题目描述:
标题:跳蚱蜢
如图 p1.png 所示: 有9只盘子,排成1个圆圈。 其中8只盘子内装着8只蚱蜢,有一个是空盘。 我们把这些蚱蜢顺时针编号为 1~8
每只蚱蜢都可以跳到相邻的空盘中, 也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。
请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列,
并且保持空盘的位置不变(也就是1-8换位,2-7换位,…),至少要经过多少次跳跃?注意:要求提交的是一个整数,请不要填写任何多余内容或说明文字。
#思路:
目前暂时还没有想到可以手算求解或者dp贪心之类的办法,于是选择暴力枚举搜索状态。
##关于本题搜索方法的技巧:
1.可以将空盘看成是标号为0或者9的盘子。
2.通过取模就可以讲数组首尾相接。
3.把其他盘子跳到空位的操作可以等价看成是把0到盘子分别可以和它左边的两个和右边的两个交换位置,既: now 号位置分别和 now-2 , now-1 , now+1 , now+2 调换位置。这种方法可以简化代码复杂度。
4.把一个描述状态的数组压缩成一个9位十进制数(状压dp思想),从而更方便判断该状态是否出现过。这样也问题就变成了如何从 s=123456789 搜索到 t=876543219。
#代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000000000
int s=123456789,t=876543219;
bool vis[maxn];
int mo[4]={-2,-1,1,2},a[10];
int get_val(int *a)
{
int sum=0;
for(int i=0;i<9;i++)
{
sum*=10;
sum+=a[i];
}
return sum;
}
int main()
{
queue<int>q;
queue<int>d;
memset(vis,0,sizeof(vis));
q.push(s);
vis[s]=1;
d.push(0);
while(!d.empty())
{
int x=q.front(),cnt=8,now,dd=d.front();;
while(x>0)
{
if(x%10==9)now=cnt;
a[cnt--]=x%10;
x/=10;
}
for(int i=0;i<4;i++)
{
int k=a[now];
a[now]=a[(now+mo[i]+9)%9];
a[(now+mo[i]+9)%9]=k;
int val=get_val(a);
if(!vis[val])
{
vis[val]=1;
if(val==t)
{
printf("ans=%d\n",dd+1);
return 0;
}
//printf("%d\n",val);
q.push(val);
d.push(dd+1);
}
k=a[now];
a[now]=a[(now+mo[i]+9)%9];
a[(now+mo[i]+9)%9]=k;
}
q.pop();
d.pop();
}
}