hdu 1043 Eight 经典八数码问题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043
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:
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:
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.
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.
题意描述:给出一个3×3的矩阵(包含1~8数字和一个字母x),经过一些移动格子上的数后得到连续的1~8,最后一格是x,要求最小移动步数。
算法分析:经典的八数码问题。八数码属于搜索方面的问题,经典解法有bfs、A*、IDA*等等。网上资料很多,这里简单介绍一下A*。
A*:f=g+h函数。g表示从起点到当前点的移动步数,h表示对当前点到目标点的最小移动步数的预测。除去起点和目标点,我们走在任意一点上的时候,下一步很容易想到应该选择f较小的继续。(对于h的计算我们可以用曼哈顿距离公式)
康托展开:这道题里面的作用在于实施hash函数,对于当前这一步后得到一个新的矩阵,用康托展开公式计算这个矩阵的hash值,用在宽搜时判断。
还有一点优化的地方:判断当前矩阵是否可以达到目标矩阵(矩阵里两个数实施交换后,逆序数的奇偶性和目标矩阵一致才可以有机会达到目标矩阵)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #define inf 0x7fffffff 10 using namespace std; 11 const int maxn=10; 12 const int M = 400000+10; 13 14 struct node 15 { 16 int mase[3][3]; 17 int x,y; 18 int f,g,h; 19 int flag; 20 friend bool operator < (node a,node b) 21 { 22 return a.f > b.f; 23 } 24 }start,tail; 25 int pre[M],v[M]; 26 27 char str[4]={'u','d','l','r' }; 28 int Can[10]={1,1,2,6,24,120,720,5040,40320 }; 29 const int destination=46234; 30 int Cantor(node cur) ///康托展开 31 { 32 int an[10],k=0; 33 for (int i=0 ;i<3 ;i++) 34 for (int j=0 ;j<3 ;j++) 35 an[k++]=cur.mase[i][j]; 36 int sum=0; 37 for (int i=0 ;i<9 ;i++) 38 { 39 int k=0; 40 for (int j=i+1 ;j<9 ;j++) 41 if (an[i]>an[j]) k++; 42 sum += k*Can[9-i-1]; 43 } 44 return sum+1; 45 } 46 47 int is_ok(node an) ///判断此时奇偶性 48 { 49 int a[10],k=0; 50 for (int i=0 ;i<3 ;i++) 51 for (int j=0 ;j<3 ;j++) 52 a[k++]=an.mase[i][j]; 53 int sum=0; 54 for (int i=0 ;i<k ;i++) if (a[i]!=0) 55 for (int j=0 ;j<i ;j++) 56 if (a[j]!=0 && a[j]>a[i]) sum ++ ; 57 if (sum&1) return 0; 58 return 1; 59 } 60 61 void print(node cur) 62 { 63 string ans; 64 int sum=destination; 65 while (pre[sum] != -1) 66 { 67 switch (v[sum]) { 68 case 0 : ans += str[0];break; 69 case 1 : ans += str[1];break; 70 case 2 : ans += str[2];break; 71 case 3 : ans += str[3];break; 72 } 73 sum=pre[sum]; 74 } 75 int len=ans.size() ; 76 for (int i=len-1 ;i>=0 ;i--) putchar(ans[i]); 77 return ; 78 } 79 80 pair<int,int> pii[10]; 81 int getH(node cur) 82 { 83 int r=0,c=0; 84 for (int i=1 ;i<=9 ;i++) 85 { 86 pii[i%9].first=r ; 87 pii[i%9].second=c; 88 c++; 89 if (c==3) {r++;c=0; } 90 } 91 int sum=0; 92 for (int i=0 ;i<3 ;i++) 93 { 94 for (int j=0 ;j<3 ;j++) 95 { 96 int u=cur.mase[i][j]; 97 sum += abs(pii[u].first-i)+abs(pii[u].second-j); 98 } 99 } 100 return sum; 101 } 102 103 int vis[M]; 104 int an[4][2]={-1,0, 1,0, 0,-1, 0,1 }; 105 void A_star(node cur) 106 { 107 priority_queue<node> Q; 108 cur.g=0 ;cur.h=getH(cur); 109 cur.f=cur.g + cur.h ; 110 cur.flag=-1; 111 Q.push(cur); 112 memset(vis,-1,sizeof(vis)); 113 memset(pre,-1,sizeof(pre)); 114 memset(v,-1,sizeof(v)); 115 vis[Cantor(cur) ]=1; 116 while (!Q.empty()) 117 { 118 cur=Q.top() ;Q.pop() ; 119 if (Cantor(cur)==destination) 120 { 121 // cout<<cur.g<<endl; 122 // for (int i=0 ;i<3 ;i++) 123 // { 124 // for (int j=0 ;j<3 ;j++) 125 // cout<<cur.mase[i][j]<<" "; 126 // cout<<endl; 127 // } 128 ///输出序列 129 print(cur); 130 return ; 131 } 132 for (int i=0 ;i<4 ;i++) 133 { 134 tail.x=cur.x+an[i][0]; 135 tail.y=cur.y+an[i][1]; 136 int x=cur.x ,y=cur.y ; 137 for (int u=0 ;u<3 ;u++) 138 for (int v=0 ;v<3 ;v++) 139 tail.mase[u][v]=cur.mase[u][v]; 140 if (tail.x<0||tail.x>=3||tail.y<0||tail.y>=3) continue; 141 swap(tail.mase[tail.x][tail.y],tail.mase[x][y]); 142 int sum=Cantor(tail); 143 if (vis[sum]==-1) 144 { 145 if (is_ok(tail)==0) continue; 146 vis[sum]=1; 147 tail.g=cur.g+1; 148 tail.h=getH(tail); 149 tail.f=tail.g+tail.h; 150 if (tail.x==x+1) tail.flag=1; 151 else if (tail.x==x-1) tail.flag=0; 152 else if (tail.y==y-1) tail.flag=2; 153 else if (tail.y==y+1) tail.flag=3; 154 pre[sum]=Cantor(cur); 155 v[sum]=i; 156 Q.push(tail); 157 } 158 } 159 } 160 return ; 161 } 162 163 int main() 164 { 165 char str[100]; 166 while (gets(str)) 167 { 168 int r=0,c=0; 169 int len=strlen(str); 170 int ok=0; 171 for (int i=0 ;i<len ;i++) 172 { 173 if (str[i]>='0' && str[i]<='9') 174 { 175 start.mase[r][c]=str[i]-'0'; 176 c++; 177 if (c==3) {r++;c=0; } 178 } 179 else if (str[i]=='x') 180 { 181 start.mase[r][c]=0; 182 start.x=r ;start.y=c ; 183 c++; 184 if (c==3) {r++;c=0; } 185 } 186 } 187 int sum=Cantor(start); 188 if (sum==destination) {printf("\n");continue; } 189 if (is_ok(start)==0) {printf("unsolvable\n");continue; } 190 A_star(start); 191 printf("\n"); 192 } 193 return 0; 194 }