POJ 1077 Eight (BFS+康托展开)详解
本题知识点和基本代码来自《算法竞赛 入门到进阶》(作者:罗勇军 郭卫斌)
如有问题欢迎巨巨们提出
题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻的数字方块可以移动到空格里。我们要求指定初始棋盘和目标棋盘,计算出最少移动次数,同时要输出数码的移动数列。初始棋盘样例已给出,目标棋盘为“1 2 3 4 5 6 7 8 x”
输入:
2 3 4 1 5 x 7 6 8
输出:
ullddrurdllurdruldr 详解:
八数码是经典的BFS问题,可以用“康托展开”判重。那什么事康托展开呢?
康托展开是一种特殊的哈希函数,针对八数码问题,康托展开完成了如表所示的工作。
状态 | 012345678 | 012345687 | 0123456768 | ...... | 876543210 |
Cantor | 0 | 1 | 2 | ...... | 362880-1 |
函数Cantor()实现的功能是:输入一个排序,即第一行的某个排序,计算它的Cantor值,即第二行的数。Cantor的时间复杂度为O(n*n),n是集合中元素的个数,利用CANTOR展开可以实现八数码的快速判重。
距离康托展开的实现原理:
例:判断2143是{1,2,3,4}的全排列中第几大的数。
计算排在2143前面的排列数目,可以转换成以下排列的和:
(1)首位小于2的所有排序,比2小的只有一个数,后面三个数的排序有3!个。
(2)首位为2,第2位小于1的所有排序,无,写成0*2!=0.
(3)前两位为21,第三位小于4的数,即2134,写成1*1!=1.
(4)前三位为214,第四位小于3的数,无,即0*0!=1.
sum=8.即2143是第八大的数。 把一个集合产生的全排列按字典序排序,第X个排序的计算公式如下:
X=a[n]*(n-1)!+a[n-1]*(n-2)!+....+a[i]*(i-1)!+...+a[2]*1!+a[1]*0![1].其中,a[i]为当前未出现的元素排在第几个。(从0开始)0<=a[i]<i. 康托展开的基础代码:
int visited[maxn] = { }; //判断改装备是否被访问过
long int factory[] = { ,,,,,,,,, };//阶乘数 bool Cantor(int str[], int n)
{
long result = ;
for (int i = ; i < n; i++)
{
int counted = ;
for (int j = i + ; j < n; j++)
{
if (str[i] > str[j])
++counted;
}
result += counted * factory[n - i - ];
}
if (!visited[result])
{
visited[result] = ;
return ;
}
else return ;
}
这道题看了很多博客,存步骤的答案方式很多,我是在结构体里设置string,然后在bfs过程中逐步保存步骤,最后输出达到最终状态的答案。看代码应该能理解。还有保存图的时候要注意,样例里空格不止一个,所以灵活点保存。我最后时间跑出来是750ms,比较慢,可用其他搜索方法优化。
AC代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<string>
#include<map>
#include<vector>
#include<ctime>
#include<stack>
using namespace std;
#define mm(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const int maxn = ;
const int inf = 0x3f3f3f3f; struct node
{
int state[];
int dis;
string ans;
}; int dir[][] = { {-,},{,-},{,},{,} };
char turn[] = { 'l','u','r','d' };
int visited[maxn] = { };
int start[];
int goal[] = {,,,,,,,,}; long int factory[] = { ,,,,,,,,, }; bool Cantor(int str[], int n)
{
long result = ;
for (int i = ; i < n; i++)
{
int counted = ;
for (int j = i + ; j < n; j++)
{
if (str[i] > str[j])
++counted;
}
result += counted * factory[n - i - ];
}
if (!visited[result])
{
visited[result] = ;
return ;
}
else return ;
} bool check(int x, int y)
{
if (x >= && x < && y >= && y < )
return true;
else return false;
} queue<char>ans; int bfs()
{
node head;
memcpy(head.state, start, sizeof(head.state));
head.dis = ;
queue<node>q;
Cantor(head.state, );
q.push(head);
while (!q.empty())
{
head = q.front();
q.pop();
int z;
for (z = ; z < ; z++)
{
if (head.state[z] == )
break;
}
int x = z % ;
int y = z / ;
for (int i = ; i < ; i++)
{
int newx = x + dir[i][];
int newy = y + dir[i][];
int nz = newx + * newy;
if (check(newx, newy))
{
node newnode = head;
swap(newnode.state[z], newnode.state[nz]); //0的交换
newnode.dis++;
if (memcmp(newnode.state, goal, sizeof(goal)) == )
{
newnode.ans = newnode.ans + turn[i];
cout << newnode.ans << endl;
return newnode.dis;
}
if (Cantor(newnode.state, ))
{
newnode.ans = head.ans + turn[i];
q.push(newnode);
}
}
}
}
return -;
} int main()
{
char s[];
cin.getline(s, );
int pos = ;
for (int i = ; s[i] != '\0'; i++)
{
if (s[i] == ' ') continue;
else if (s[i] == 'x') start[pos++] = ;
else start[pos++] = s[i] - '';
}
int num = bfs();
//printf("%d\n", num);
if (num == -) printf("unsolvable\n");
return ;
}
POJ 1077 Eight (BFS+康托展开)详解的更多相关文章
- HDU 1043 & POJ 1077 Eight(康托展开+BFS+预处理)
Eight Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 30176 Accepted: 13119 Special ...
- HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)
Eight Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 30176 Accepted: 13119 Special ...
- 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: 1000 ...
- BFS和DFS详解
BFS和DFS详解以及java实现 前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问 ...
- HDU_1043 Eight 【逆向BFS + 康托展开 】【A* + 康托展开 】
一.题目 http://acm.hdu.edu.cn/showproblem.php?pid=1043 二.两种方法 该题很明显,是一个八数码的问题,就是9宫格,里面有一个空格,外加1~8的数字,任意 ...
- POJ 1077 && HDU 1043 Eight A*算法,bfs,康托展开,hash 难度:3
http://poj.org/problem?id=1077 http://acm.hdu.edu.cn/showproblem.php?pid=1043 X=a[n]*(n-1)!+a[n-1]*( ...
- Poj 1077 eight(BFS+全序列Hash解八数码问题)
一.题意 经典的八数码问题,有人说不做此题人生不完整,哈哈.给出一个含数字1~8和字母x的3 * 3矩阵,如: 1 2 X 3 4 6 7 5 8 ...
- Aizu0121 Seven Puzzle(bfs+康托展开)
https://vjudge.net/problem/Aizu-0121 比八数码要水的多,bfs. 但是做的时候我把康托展开记错了,wa了好几次. 附上康托展开博客详解:https://blog.c ...
- HDU - 1430 魔板 【BFS + 康托展开 + 哈希】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1430 思路 我刚开始 想到的 就是 康托展开 但是这个题目是 多组输入 即使用 康托展开 也是会T的 ...
随机推荐
- 在Linux - Centos上安装Python3(上)
必看内容 在Linux上安装Python常用的2种方法 1.Python源码编译安装,有点复杂,适合老司机 2.从EPEL/IUS仓库安装,新手建议使用些方法,比较简单,目前2019-07-31提供最 ...
- 【iOS】tableView:viewForHeaderInSection: 方法未调用
今天遇到这个问题,即重写的方法 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)sec ...
- 模拟器无Back、Menu等键
问题如图所示: 解决方法: 1. 打开Android Virtual Device (AVD) Manager --> 选择模拟器,并点击edit --> 勾选KeyBoard中的选项,并 ...
- 反应式微服务框架Flower
Flower是一个构建在Akka上的反应式微服务框架,开发者只需要针对每一个细粒度的业务功能开发一个Service服务,并将这些Service按照业务流程进行可视化编排,即可得到一个反应式系统. 即时 ...
- JDBC连接池-C3P0连接
JDBC连接池-C3P0连接 c3p0连接池的学习英语好的看英文原版 c3p0 - JDBC3 Connection and Statement Pooling 使用c3p0连接池 三种方 ...
- Vue监听键盘回车事件
在写页面时遇见了登录页需要加一个键盘回车事件. vue 的 v-on中有这样的修饰符 <input v-on:keyup.enter="submit"> 即<in ...
- kube-proxy源码解析
kubernetes离线安装包,仅需三步 kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源码解析为主,如果想去了解iptables模式的原理 ...
- java基本数据类型和包装类之间的区别
1.声明方式不同,基本类型不适用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间: 2.存储方式及位置不同,基本类型是直接将变量值存储在堆栈中,而包装类型是将对象放在堆中,然后通过引用 ...
- CodeGlance右侧窗口缩略图消失不见
说明下问题,idea中的CodeGlance插件会在右侧显示缩略图,可以快速定位代码.今天遇到个问题升级了插件后右侧窗口消失.经过卸载插件,重启,reset一系列操作后还是没能恢复. 能去搜索引擎搜索 ...
- kubernetes API服务器的安全防护
12.1.了解认证机制 启动API服务器时,通过命令行选项可以开启认证插件. 12.1.1.用户和组 了解用户: 分为两种连接到api服务器的客户端: 1.真实的人 2.pod,使用一种称为Servi ...