时间限制:1.0s 内存限制:256.0MB
问题描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
123.46758
样例输出
3
样例输入
13524678.
46758123.
46758123.
样例输出
22
广搜题,对我来说这道题判重的方法是我最值得掌握的, 之前我自己是用二位数组判重,没产生一个新的序列就遍历一次二位数组,看有没有相同的,没有就入队列等等。。
但是非常耗时,绝对会超时。
然后,大神教我用字典树的方法判重,这样效率就大大提高。字典树只在上个学期写过一两次。嗯 学到了。
#include <stdio.h>
#include <queue>
#include <string.h>
using namespace std;
struct node
{
char s[10];
int step;
};
struct N
{
N *next[9];
N()
{//构造函数
int i;
for(i = 0; i < 9; i++)
next[i] = NULL;
}
};
char a[10], b[10];
queue<node> q;
node sta;
char end[10];
int des[4] = {1, -1, 3, -3};//方向数组
int vis(N *head, char x[])
{//判重
int i, ok = 1;
N *temp = head;
for(i = 0; i < 9; i++)
{
int t;
if(x[i] != '.')
t = x[i] - '0';
else
t = 0;//.对应next[0]的位置
if(temp->next[t] == NULL)
{//说明这种排列之前没有出现过
ok = 0;
N* e = new N;//别忘申请空间
temp->next[t] = e;
}
temp = temp ->next[t];
}
return ok;//ok为代表出现过,ok为0是没有出现过
}
int bfs()
{
N* head = new N;//之前忘了申请空间= =
node e, e1;
int ok = vis(head, sta.s);
sta.step = 0;
q.push(sta);
while(!q.empty())
{
e = q.front();
q.pop();
int i, pos, newp;
for(i = 0; i < 9; i++)
{//找到.的位置
if(e.s[i] == '.')
{
pos = i;
break;
}
}
for(i = 0; i < 4; i++)
{
if(pos % 3 == 0 && des[i] == -1 || pos % 3 == 2 && des[i] == 1)
{
continue;
}
newp = pos + des[i];
if(newp < 0 || newp > 8)
{
continue;
}
strcpy(e1.s, e.s);
e1.s[newp] = '.';
e1.s[pos] = e.s[newp];
e1.step = e.step + 1;
//printf("%d\n", e1.step);
if(strcmp(e1.s, end) == 0)
{
return e1.step;
}
else
{
if(vis(head, e1.s) == 0)
q.push(e1);
}
}
}
return 0;
}
int main (void)
{
while(scanf("%s %s", sta.s, end) != EOF)
{
while(!q.empty())
q.pop();
printf("%d\n", bfs());
}
return 0;
}