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:
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 xwhere 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
1 2 3
x 4 6
7 5 8
is described by this list:
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 }