本题知识点和基本代码来自《算法竞赛 入门到进阶》(作者:罗勇军 郭卫斌)

如有问题欢迎巨巨们提出

题意:八数码问题是在一个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+康托展开)详解的更多相关文章

  1. HDU 1043 & POJ 1077 Eight(康托展开+BFS+预处理)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  2. HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  3. 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 ...

  4. BFS和DFS详解

    BFS和DFS详解以及java实现 前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问 ...

  5. HDU_1043 Eight 【逆向BFS + 康托展开 】【A* + 康托展开 】

    一.题目 http://acm.hdu.edu.cn/showproblem.php?pid=1043 二.两种方法 该题很明显,是一个八数码的问题,就是9宫格,里面有一个空格,外加1~8的数字,任意 ...

  6. 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]*( ...

  7. Poj 1077 eight(BFS+全序列Hash解八数码问题)

    一.题意 经典的八数码问题,有人说不做此题人生不完整,哈哈.给出一个含数字1~8和字母x的3 * 3矩阵,如: 1  2  X            3 4  6            7  5  8 ...

  8. Aizu0121 Seven Puzzle(bfs+康托展开)

    https://vjudge.net/problem/Aizu-0121 比八数码要水的多,bfs. 但是做的时候我把康托展开记错了,wa了好几次. 附上康托展开博客详解:https://blog.c ...

  9. HDU - 1430 魔板 【BFS + 康托展开 + 哈希】

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1430 思路 我刚开始 想到的 就是 康托展开 但是这个题目是 多组输入 即使用 康托展开 也是会T的 ...

随机推荐

  1. 【WPF】 InkCanvas 书写毛笔效果

    首先贴出本文参考学习的文章吧. https://www.cnblogs.com/LCHL/p/9055642.html#4206298 感谢这位懒羊羊的代码和讲解(下简称羊博主),我在此基础上稍微加了 ...

  2. 【Android Studio】提示代码忽略大小写

    在 Preference... 中找到如下,设置 Case sensitive completion 为 None 即可,如下图: PS: 该截图是 Intellij IDEA (Android St ...

  3. Android Studio 设置/更改 SDK 路径

    网上看到有人说需要重启 Android Studio,感觉麻烦,就自己试了试其他方法,果然还是有的! 很简单,只需打开 File 菜单下的 Project Structure 就可以设置了,如图所示:

  4. 【Java例题】4.1 级数求和1

    1. 计算级数之和: y=1-1/2+1/4-1/8+...+ (-1)^(n-1)/2^(n-1). 这里的"^"表示乘方. package chapter4; import j ...

  5. win10 我的电脑下面的六个文件夹的隐藏

      第一步   第二步     第三步 修改注册表,要隐藏那个文件夹,ThisPCPolicy 改为 "Hide" 修改我的文档的注册表值,使我的文档文件夹隐藏     <w ...

  6. HTML/CSS:图片居中(水平居中和垂直居中)

    css图片居中(水平居中和垂直居中) css图片居中分css图片水平居中和垂直居中两种情况,有时候还需要图片同时水平垂直居中, 下面分几种居中情况分别介绍: css图片水平居中 1.利用margin: ...

  7. .netcore持续集成测试篇之搭建内存服务器进行集成测试一

    系列目录 在web项目里,我们把每一层的代码的单元测试都通过并不代表程序能正常运行,因为这个过程缺失了http管道,很多时候我们还还需要把项目布在iis环境中或者在vs里启动iis express服务 ...

  8. Asp.Net Core WebAPI+PostgreSQL部署在Docker中

     PostgreSQL是一个功能强大的开源数据库系统.它支持了大多数的SQL:2008标准的数据类型,包括整型.数值值.布尔型.字节型.字符型.日期型.时间间隔型和时间型,它也支持存储二进制的大对像, ...

  9. MySQL学习随笔记录

    安装选custmer自定义安装.默认安装全部在c盘.自定义安装的时候有个advance port选项用来选择安装目录. -----------------------MySQL常见的一些操作命令--- ...

  10. pythonday05数据类型(三)

    ---恢复内容开始--- 今日内容 1.字典 2.强制转换 3.习题讲解 1.字典 帮助用户去表示一个事物的信息(事物是有多个属性). info = {"name":'刘伟达',' ...