poj 1077 八数码(BFS+康托展开)


  1 /*
2 题意:八数码问题,给出3*3的矩阵含1~8以及x,给出一个符合的解使得移动后的矩阵的顺序为1~8,最后为x
3
4 题解:BFS
5 需要用到康托展开来表示状态,不然数组无法完全表示所有状态,这样BFS就无法判断找不到解的情况(status
6 的0ms,0KB究竟是怎么做到的,简直不能想象=。=)
7 */
8 #include <cstdio>
9 #include <cstring>
10 #include <queue>
11 #include <stack>
12 #include <algorithm>
13
14 using namespace std;
15
16 int fac[] = {1,1,2,6,24,120,720,5040,40320,362880}; //i的阶乘为fac[i]
17 /* 康托展开.
18 {1...n}的全排列由小到大有序,s[]为第几个数 */
19 int KT(int n, int s[])
20 {
21 int i, j, t, sum;
22 sum = 0;
23 for (i=0; i<n; i++)
24 {
25 t = 0;
26 for (j=i+1; j<n; j++)
27 if (s[j] < s[i])
28 t++;
29 sum += t*fac[n-i-1];
30 }
31 return sum+1;
32 }
33
34 /* 康托展开的逆运算.
35 {1...n}的全排列,中的第k个数为s[] */
36 void invKT(int n, int k, int s[])
37 {
38 int i, j, t, vst[10]={0};
39 k--;
40 for (i=0; i<n; i++)
41 {
42 t = k/fac[n-i-1];
43 for (j=1; j<=n; j++)
44 if (!vst[j])
45 {
46 if (t == 0) break;
47 t--;
48 }
49 s[i] = j;
50 vst[j] = 1;
51 k %= fac[n-i-1];
52 }
53 }
54
55 int dir[4][2]={0,1,0,-1,1,0,-1,0};
56
57 int vis[370000];
58 char path[370000];
59 char ansstr[370000];
60
61 struct node
62 {
63 int state,pdir;
64 int x,y;
65 }Q[370000];
66 int front,tail;
67
68 int finish_state;
69
70 int bfs(node start)
71 {
72 memset(vis,-1,sizeof(vis));
73 vis[start.state] = 100000000;
74 front = tail = 0;
75 Q[tail++] = start;
76 while (front < tail)
77 {
78 node now = Q[front++];
79 if (now.state == finish_state)
80 return finish_state;
81 for(int i=0; i<4; i++)
82 {
83 node tmp = now;
84 if (tmp.pdir != i)
85 {
86 int s[10];
87 invKT(9,tmp.state,s);
88
89 int x = now.x, y = now.y;
90 int nx = x+dir[i][0],ny = y+dir[i][1];
91 if (0<=nx&&nx<=2 && 0<=ny&&ny<=2)
92 {
93 swap(s[x*3+y],s[nx*3+ny]);
94 tmp.pdir = i;
95 tmp.x = nx;
96 tmp.y = ny;
97 tmp.state = KT(9,s);
98 if (vis[tmp.state] != -1)
99 continue;
100 Q[tail++] = tmp;
101 vis[tmp.state] = now.state;
102 char c;
103 switch(i)
104 {
105 case 0:c = ‘r‘; break;
106 case 1:c = ‘l‘; break;
107 case 2:c = ‘d‘; break;
108 case 3:c = ‘u‘; break;
109 }
110 path[tmp.state] = c;
111 }
112 }
113 }
114 }
115 return -1;
116 }
117
118 int main(void)
119 {
120 char str[50],tstr[3];
121 int tmps[9]={1,2,3,4,5,6,7,8,9};
122 while (~scanf("%s",tstr))
123 {
124 str[0] = tstr[0];
125 for(int i=1; i<9; i++)
126 {
127 scanf("%s",tstr);
128 str[i*2] = tstr[0];
129 }
130 int s[9];
131 int x;
132 for(int i=0; i<9; i++)
133 {
134 if (‘1‘<=str[i*2] && str[i*2]<=‘9‘)
135 s[i] = str[i*2]-‘0‘;
136 else
137 {
138 s[i] = 9;
139 x = i;
140 }
141 }
142 // 输入略恶心,最后用s[]记录矩阵
143 node start;
144 start.pdir = -1;
145 start.x = x/3;
146 start.y = x%3;
147 start.state = KT(9,s);
148
149 finish_state = KT(9,tmps);
150 int ans = bfs(start);
151
152 if (ans < 0)
153 {
154 printf("unsolvable\n");
155 }
156 else
157 {
158 int sum = 0;
159 while (vis[finish_state] != -1)
160 {
161 if (vis[finish_state] == 100000000)
162 break;
163 ansstr[sum++] = path[finish_state];
164 finish_state = vis[finish_state];
165 }
166 ansstr[sum] = 0;
167
168 for(int i = sum-1; i>=0; i--)
169 printf("%c",ansstr[i]);
170 printf("\n");
171 }
172 }
173 return 0;
174 }

poj 1077 八数码(BFS+康托展开),布布扣,bubuko.com

时间: 2024-10-21 14:52:59

poj 1077 八数码(BFS+康托展开)的相关文章

POJ 1077 Eight(bfs+康托展开)

Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 41040   Accepted: 16901   Special Judge 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

HDU 1043 POJ 1077 八数码问题

以下内容转载自:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 八数码的八境界 研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor ove

poj 1077 八数码

这道题花了我一晚上去了看了一种解法,结果最后悲剧了,只在poj上过了,在hdu上TLE,原因是因为hdu上是多组数 据,而poj上是一组数据...悲剧啊,学的方法有点低效... 不过那个打印路径方法倒是可以借鉴一下,从终点往起点递归,打印路径... 贴代码: #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> using namespace std; #define

poj 1077 Eight(双向bfs)

题目链接:http://poj.org/problem?id=1077 思路分析:题目要求在找出最短的移动路径,使得从给定的状态到达最终状态. <1>搜索算法选择:由于需要找出最短的移动路径,所以选择bfs搜索 <2>判重方法: 将空格视为数字9,则可以将状态的集合视为1-9的排列组合的集合,根据康托展开,将每一个状态映射到一个正整数中: 在由哈希表进行判重. <3>状态压缩:在搜索时使用将每个状态转换为一个由1-9组成的9位数字即可进行状态压缩与解压. <4&g

HDU 1043 Eight(双向BFS+康托展开)

http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用双向BFS来做. ①双向BFS 在单向BFS的基础上,多建一个从终止状态开始搜索的队列,当然这个时候需要两个vis[]辅助数组,分别记录两个队列的访问情况,当两个队列相遇时即可终止循环. ②康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[

HDU1043 八数码(BFS + 打表)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 , 康托展开 + BFS + 打表. 经典八数码问题,传说此题不做人生不完整,关于八数码的八境界:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 我自己是用哈希(康托展开) + BFS  + 打表过的,第三重境界. 由于一些高级的搜索现在还没学,所以目前能升级的也就是用双向BFS来做了,等过几天有心情了来做. 本文

【HDU - 1043】Eight(反向bfs+康托展开)

Eight Descriptions: 简单介绍一下八数码问题:在一个3×3的九宫格上,填有1~8八个数字,空余一个位置,例如下图: 1 2 3 4 5 6 7 8   在上图中,由于右下角位置是空的,你可以移动数字,比如可以将数字6下移一位: 1 2 3   1 2 3 4 5 6 → 4 5   7 8     7 8 6 或者将数字8右移一位: 1 2 3   1 2 3 4 5 6 → 4 5 6 7 8     7   8 1~8按顺序排列的情况称为"初始状态"(如最上方图)

hdu 1430 (BFS 康托展开 或 map )

第一眼看到这题就直接BFS爆搜,第一发爆了内存,傻逼了忘标记了,然后就改,咋标记呢. 然后想到用map函数,就8!个不同的排列,换成字符串用map标记.然后又交一发果断超时,伤心,最恨超时,还不如来个wa算了. 然后卡着了,后来上网上搜了,要用康托展开,康托展开是什么鬼?然后学习了一下,就是个映射,感觉和map差不多. http://blog.csdn.net/zhongkeli/article/details/6966805这个学习一下康托展开. 其实本题的关键不是康托展开,而是置换. 以12

hdu 5012 bfs 康托展开

Dice Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 491    Accepted Submission(s): 290 Problem Description There are 2 special dices on the table. On each face of the dice, a distinct number w