hdu 1043 pku poj 1077 Eight (BFS + 康拓展开)

http://acm.hdu.edu.cn/showproblem.php?pid=1043

http://poj.org/problem?id=1077

Eight

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9173    Accepted Submission(s): 2473 Special Judge

Problem Description
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15  x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
 1  2  3  4     1  2  3  4     1  2  3  4     1  2  3  4  5  6  7  8     5  6  7  8     5  6  7  8     5  6  7  8  9  x 10 12     9 10  x 12     9 10 11 12     9 10 11 12 13 14 11 15    13 14 11 15    13 14  x 15    13 14 15  x             r->            d->            r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
 
Input
You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
 
Output
You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
 
Sample Input
2 3 4 1 5 x 7 6 8
 
Sample Output
ullddrurdllurdruldr
 
思路:
八数码问题,我喜欢跟康拓展开联系在一起;
这里解释下康拓展开:

{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个。123 132 213 231 312 321 。

代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。

他们间的对应关系可由康托展开来找到。

如我想知道321是{1,2,3}中第几个大的数可以这样考虑 :

第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,

所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。 2*2!+1*1!+0*0!就是康托展开。

再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,

所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。

 
先DFS从:
1 2 3
4 5 6  --->  到所有状态 都事先搜索出来 ,然后用 输入的状态 去中间 回溯查找 需要得到的状态 即可
7 8 x
AC代码:
(提示POJ请用G++提交,用C++在POJ会超时的,我想了原因,可能是STL容器在C++中的耗时远大于G++)
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <queue>
  4 #include <string.h>
  5 
  6 using namespace std;
  7 #define N 363000
  8 
  9 struct Nod
 10 {
 11     int b[10];
 12     int x,y,pos;
 13 }nd1,nd2;
 14 
 15 int fac[] = {1,1,2,6,24,120,720,5040,40320,362880};  //康拓展开用到的数组
 16  //康托展开:
 17 int cantor(int* a, int k)
 18 {
 19      int i, j, tmp, num = 0;
 20      for (i = 0; i < k; i++) {
 21          tmp = 0;
 22          for (j = i + 1; j < k; j++)
 23              if (a[j] < a[i])
 24                  tmp++;
 25          num += fac[k - i - 1] * tmp;
 26      }
 27      return num;
 28 }
 29 
 30 int mark[N],pre[N];
 31 char dir[N];
 32 int cx[]={0,0,1,-1};
 33 int cy[]={-1,1,0,0};
 34 
 35 void exchange(int *a,int x,int y)
 36 {
 37     int temp=a[x];
 38     a[x]=a[y];
 39     a[y]=temp;
 40 }
 41 
 42 void bfs(int *b,int x,int y)
 43 {
 44     queue<Nod> q;
 45     memset(mark,0,sizeof(mark));
 46     memset(pre,-1,sizeof(pre));
 47     nd1.x=x;
 48     nd1.y=y;
 49     memcpy(nd1.b,b,sizeof(int)*10);
 50     int i,temp;
 51     temp = cantor(b,9);
 52     mark[temp] = 1;
 53     nd1.pos = temp;
 54     q.push(nd1);
 55     while(!q.empty())
 56     {
 57         nd2 = q.front();
 58         q.pop();
 59         for(i=0;i<4;i++)
 60         {
 61             nd1.x = nd2.x + cx[i];
 62             nd1.y = nd2.y + cy[i];
 63             if(nd1.x>=0&&nd1.x<3&&nd1.y>=0&&nd1.y<3)
 64             {
 65                 memcpy(nd1.b,nd2.b,sizeof(int)*10);
 66                 exchange(nd1.b,nd1.x*3+nd1.y,nd2.x*3+nd2.y);
 67                 temp = cantor(nd1.b,9);
 68                 nd1.pos = temp;
 69                 if(mark[temp]==1)  continue;
 70                 mark[temp] = 1;
 71                 pre[temp] = nd2.pos;
 72                 if(cx[i]==0)
 73                 {
 74                     if(cy[i]==1)   dir[temp] = 'l';   //因为是从目标状态开始搜索的,最后需要倒序输出,然后方向也应该是相反输出
 75                     else    dir[temp] = 'r';    //dir[temp] = 'l' 的反方向
 76                 }
 77                 if(cy[i]==0)
 78                 {
 79                     if(cx[i]==1)   dir[temp] = 'u';  //同上
 80                     else    dir[temp] = 'd';  //同上
 81                 }
 82                 q.push(nd1);
 83             }
 84         }
 85     }
 86 }
 87 
 88 int main()
 89 {
 90     char str[5];
 91     int a[10],b[10]={1,2,3,4,5,6,7,8,9};  //末状态,从末状态开始搜索
 92     bfs(b,2,2);  //预先搜索所有状态
 93     while(~scanf("%s",str))
 94     {
 95         if(str[0]=='x')  a[0]=9;
 96         else a[0]=str[0]-'0';
 97         int i;
 98         for(i=1;i<9;i++)
 99         {
100             scanf("%s",str);
101             if(str[0]=='x')   a[i]=9;
102             else    a[i]=str[0]-'0';
103         }
104         int temp = cantor(a,9);  //得到起始状态,然后回溯到末状态
105         if(!mark[temp])  //所有状态里面若没有起始状态,则为不可达
106         {
107             printf("unsolvable\n");
108             continue;
109         }
110         while(temp)  //回溯过程
111         {
112             printf("%c",dir[temp]);
113             temp = pre[temp];
114         }
115         putchar(10);
116     }
117     return 0;
118 }

 

posted @ 2013-07-25 16:06  crazy_apple  阅读(418)  评论(0编辑  收藏  举报