九宫重排

来源:互联网 发布:3g与4g网络消耗流量 编辑:程序博客网 时间:2024/04/27 13:55

时间限制:1.0s   内存限制:256.0MB
问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
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';elset = 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;} 






0 0