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的 ...
随机推荐
- 模块购物商城和ATM机代码:
http://outofmemory.cn/python/video/let-us-python/ python为程序员服务 快来加入群[python爬虫交流群](群号570070796),发现精彩 ...
- RabbitMQ(四):使用Docker构建RabbitMQ高可用负载均衡集群
本文使用Docker搭建RabbitMQ集群,然后使用HAProxy做负载均衡,最后使用KeepAlived实现集群高可用,从而搭建起来一个完成了RabbitMQ高可用负载均衡集群.受限于自身条件,本 ...
- golang const 内itoa 用法详解及优劣分析
首先itoa 是什么 const 内的 iota是golang语言的常量计数器,只能在常量的表达式中使用,,即const内. iota在const关键字出现时将被重置为0(const内部的第一行之前) ...
- JAVA面向对象面试题带答案(墙裂推荐)
1) 在Java中,如果父类中的某些方法不包含任何逻辑,并且需要有子类重写,应该使用(c)关键字来申明父类的这些方法. a) Finalc b) Static c) Abstract d) Void2 ...
- C#实现简单爬虫
分享之前写过的一个爬虫,采集数据,存入数据库的简单实现. github地址:https://github.com/CodesCreator/biu-biu-biu-
- mac 下 docker 镜像加速器
配置镜像加速器 具体设置见下图即可. 
- Web很脆弱,SQL注入要了解
SQL注入 所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令. 通过一下的例子更形象的了解SQL注入: 有一个Login ...
- LeetCode——409. Longest Palindrome
题目: Given a string which consists of lowercase or uppercase letters, find the length of the longest ...
- C#之BackgroundWorker从简单入门到深入精通的用法总结
需求分析 经常用到的耗时操作,例如: 1.文件下载和上载(包括点对点应用程序传输文件,从网络下载文件.图像等)2.数据库事务(从数据库读到大量的数据到WinForm界面中的DataGridview里呈 ...
- (二十二)c#Winform自定义控件-半透明窗体
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...