题意:
如下图所示,从上到下从左到右,给出3*3矩阵的数字摆放起始情况..
输出最少经过几步可以把这个矩阵变成0123456789的形式..其中0表示空格..
如果无法变成0123456789就输出NO..
思路:
求最少几步可以变成0123456789一下子就想到了广搜..
但是用广搜的时候会需要一个数组vis[]记录当前状态已经搜过了,不需要继续搜..但是用vis[0][1][2][3][4][5][6][7][8][9]这样的话会超内存..
所以就用康拓展开来记录状态..
康拓展开就是通过公式计算出该数在总序列里的序号..
举个例子
123这个排列
有如下排列方式
排列数 序号
123 1
132 2
213 3
231 4
312 5
321 6
其实就是全排列的字典序
用那个公式得到123的值就是1
根据序号得到该排列数..一个排列数表示了八数码的状态..
广搜的时候就把0123456789当成是初始状态..看一下是否可以搜到结果状态..
可以就输出最小值..如果初始状态就是0123456789就直接输出0..
广搜的时候就看一下可以往哪里移动且移动后的状态是没有出现过的..
最后就可以得到最少使用的次数了..
Tips:
///X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
康拓展开..
开一个vis[9!]的数组就可以记录所有的状态了..
康拓展开运用举例..
0213
X=0*3! + 1*2! + 0*1!
那个an表示从右向左数第N个数字后面有几个比他小的
例如
54321
a5 = 4
Code:
1 #include <iostream> 2 #include <algorithm> 3 #include <stdio.h> 4 #include <queue> 5 #include <cstring> 6 using namespace std; 7 #define clr(x) memset(x, 0, sizeof(x)) 8 9 ///X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 10 11 struct Num 12 { 13 char num[10]; 14 int cnt; 15 }; 16 17 bool vis[363000]; 18 int cnt[363000]; 19 int cha[4] = {-3, -1, 1, 3}; 20 int qpl[9] = {40320, 5040, 720, 120, 24, 6, 2, 1, 1}; 21 int fac[10]={1,1,2,6,24,120,720,5040,40320,362880}; 22 int kt(char*s) 23 { 24 int i,j,t; 25 int num=0; 26 for(i=0;i<8;i++) 27 { 28 t=0; 29 for(j=i+1;j<9;j++) 30 if(s[j]<s[i]) 31 t++; 32 num+=fac[8-i]*t; 33 } 34 return num; 35 } 36 37 int check(char *arr) 38 { 39 for(int i = 0; i < 9; ++i) 40 if(arr[i] == '0') return i; 41 } 42 43 void bfs() { 44 queue<Num> Q; 45 Num tmp, tmp1; 46 strcpy(tmp.num, "012345678"), tmp.cnt = 0; 47 Q.push(tmp); 48 tmp = Q.front(); 49 int tmpn; 50 vis[0] = true; 51 int res = 0; 52 while(!Q.empty()) { 53 tmp = Q.front(); 54 int x = kt(tmp.num); 55 Q.pop(); 56 int pos = check(tmp.num); 57 if (pos >= 3){ 58 swap(tmp.num[pos],tmp.num[pos-3]); 59 tmpn = kt(tmp.num); 60 if (!vis[tmpn]){ 61 cnt[tmpn] = cnt[x]+1; 62 if (cnt[tmpn]>res) 63 res = cnt[tmpn]; 64 vis[tmpn] = true; 65 Q.push(tmp); 66 } 67 swap(tmp.num[pos],tmp.num[pos-3]); 68 } 69 if (pos <= 5){ 70 swap(tmp.num[pos],tmp.num[pos+3]); 71 tmpn = kt(tmp.num); 72 if (!vis[tmpn]){ 73 cnt[tmpn] = cnt[x]+1; 74 if (cnt[tmpn]>res) 75 res = cnt[tmpn]; 76 vis[tmpn] = true; 77 Q.push(tmp); 78 } 79 swap(tmp.num[pos],tmp.num[pos+3]); 80 } 81 if (pos%3!=0){ 82 swap(tmp.num[pos],tmp.num[pos-1]); 83 tmpn = kt(tmp.num); 84 if (!vis[tmpn]){ 85 cnt[tmpn] = cnt[x]+1; 86 if (cnt[tmpn]>res) 87 res = cnt[tmpn]; 88 vis[tmpn] = true; 89 Q.push(tmp); 90 } 91 swap(tmp.num[pos],tmp.num[pos-1]); 92 } 93 if (pos%3 != 2){ 94 swap(tmp.num[pos],tmp.num[pos+1]); 95 tmpn = kt(tmp.num); 96 if (!vis[tmpn]){ 97 cnt[tmpn] = cnt[x]+1; 98 if (cnt[tmpn]>res) 99 res = cnt[tmpn]; 100 vis[tmpn] = true; 101 Q.push(tmp); 102 } 103 swap(tmp.num[pos],tmp.num[pos+1]); 104 } 105 } 106 } 107 108 int main() 109 { 110 clr(vis); 111 clr(cnt); 112 queue<Num> Q; 113 bool flag; 114 bfs(); 115 char num[10]; 116 while(EOF != scanf("%s", num)) { 117 int tmp = kt(num); 118 if(cnt[tmp] || tmp ==0) printf("%d\n", cnt[tmp]); 119 else puts("NO"); 120 } 121 return 0; 122 }
链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1049