[Luogu1379]八数码难题
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入输出格式
输入格式:
输入初始状态,一行九个数字,空格用0表示
输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输入输出样例
283104765
4
普通搜索7000ms
#include <cstdio>
#include <iostream>
#include <queue>
#include <map>
using namespace std;
#define reg register
#define ll long long
ll St, Ed;
map<ll, int> vis;
struct date {
ll hsh;
int stp;
};
const int dx[] = {, , -, , }, dy[] = {, , , , -};
int main()
{
scanf("%lld", &St);
Ed = ;
queue <date> q;
q.push((date){St, });
while(!q.empty())
{
ll hsh = q.front().hsh;
int tp = q.front().stp;
q.pop();
if (hsh == Ed) {
printf("%d\n", tp);
return ;
}
int a[][];
int tmp = hsh;
for (reg int i = ; i >= ; i --)
for (reg int j = ; j >= ; j --)
a[i][j] = tmp % , tmp /= ;
int x = , y = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
if (!a[i][j]) {x = i, y = j;break;}
for (reg int i = ; i <= ; i ++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx <= or tx > or ty <= or ty > ) continue;
swap(a[x][y], a[tx][ty]);
int nhsh = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
nhsh = nhsh * + a[i][j];
if (!vis[nhsh]) vis[nhsh] = , q.push((date){nhsh, tp + });
swap(a[x][y], a[tx][ty]);
}
}
return ;
}
双向广搜242ms
#include <cstdio>
#include <iostream>
#include <queue>
#include <map>
using namespace std;
#define reg register
#define ll long long
ll St, Ed;
map<ll, int> vis1, vis2;
struct date {
ll hsh;
int stp;
};
const int dx[] = {, , -, , }, dy[] = {, , , , -};
int main()
{
scanf("%lld", &St);
Ed = ;
queue <date> q1, q2;
q1.push((date){St, });
q2.push((date){Ed, });
vis1[St] = , vis2[Ed] = ;
if (St == Ed) return puts(""), ;
while(!q1.empty() and !q2.empty())
{
ll hsh = q1.front().hsh;
int tp = q1.front().stp;
q1.pop();
if (vis2[hsh]) {
printf("%d\n", tp + vis2[hsh]);
return ;
}
int a[][];
int tmp = hsh;
for (reg int i = ; i >= ; i --)
for (reg int j = ; j >= ; j --)
a[i][j] = tmp % , tmp /= ;
int x = , y = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
if (!a[i][j]) {x = i, y = j;break;}
for (reg int i = ; i <= ; i ++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx <= or tx > or ty <= or ty > ) continue;
swap(a[x][y], a[tx][ty]);
int nhsh = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
nhsh = nhsh * + a[i][j];
if (!vis1[nhsh]) vis1[nhsh] = tp + , q1.push((date){nhsh, tp + });
swap(a[x][y], a[tx][ty]);
}
hsh = q2.front().hsh;
tp = q2.front().stp;
q2.pop();
if (vis1[hsh]) {
printf("%d\n", tp + vis1[hsh]);
return ;
}
tmp = hsh;
for (reg int i = ; i >= ; i --)
for (reg int j = ; j >= ; j --)
a[i][j] = tmp % , tmp /= ;
x = , y = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
if (!a[i][j]) {x = i, y = j;break;}
for (reg int i = ; i <= ; i ++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx <= or tx > or ty <= or ty > ) continue;
swap(a[x][y], a[tx][ty]);
int nhsh = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
nhsh = nhsh * + a[i][j];
if (!vis2[nhsh]) vis2[nhsh] = tp + , q2.push((date){nhsh, tp + });
swap(a[x][y], a[tx][ty]);
}
}
return ;
}
[Luogu1379]八数码难题的更多相关文章
- 双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启 ...
- Codevs 1225 八数码难题
1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的 ...
- [luogu]P1379 八数码难题[广度优先搜索]
八数码难题 ——!x^n+y^n=z^n 我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…) 各位如果想用IDA*的可以看看 ...
- 洛谷P1379八数码难题
题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...
- 洛谷 P1379 八数码难题 解题报告
P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...
- 【洛谷P1379】八数码难题(广搜、A*)
八数码难题 题目描述 一.广搜: 首先要考虑用什么存每一个状态 显然每个状态都用一个矩阵存是很麻烦的. 我们可以考虑将一个3*3的矩阵用一个字符串或long long 存. 每次扩展时再转化为矩阵. ...
- 习题:八数码难题(双向BFS)
八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...
- 「LuoguP1379」 八数码难题(迭代加深
[P1379]八数码难题 - 洛谷 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种 ...
- 洛谷——P1379 八数码难题
P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...
随机推荐
- 【转载】pandas中的循环
原始文章链接: https://towardsdatascience.com/how-to-make-your-pandas-loop-71-803-times-faster-805030df4f06 ...
- NOIP2009 1.多项式输出
题目: 其中,aixi称为 i 次项,ai 称为 i 次项的系数.给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式: 1. 多项式中自变量为 x,从左到右按照次数递减顺序给出多 ...
- js 手机号码正则表达式
var chenkPhone=/^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/var username=$ ...
- Metasploit工具----漏洞利用模块
漏洞利用是指由渗透测试者利用一个系统.应用或者服务中的安全漏洞进行的攻击行为.流行的渗透攻击技术包括缓冲区溢出.Web应用程序攻击,以及利用配置错误等,其中包含攻击者或测试人员针对系统中的漏洞而设计的 ...
- ansible-playbook流程控制-loops循环使用
1. ansible-playbook流程控制-loops循环使用 有时你想要多次重复任务.在计算机编程中,这称为循环.common ansible循环包括使用文件模块更改多个文件和/或目录的所 ...
- [工具][vim] vim设置显示行号
转载自:electrocrazy的博客 在linux环境下,vim是常用的代码查看和编辑工具.在程序编译出错时,一般会提示出错的行号,但是用vim打开的代码确不显示行号,错误语句的定位非常不便.那么怎 ...
- Redis专题(3):锁的基本概念到Redis分布式锁实现
拓展阅读:Redis闲谈(1):构建知识图谱 Redis专题(2):Redis数据结构底层探秘 近来,分布式的问题被广泛提及,比如分布式事务.分布式框架.ZooKeeper.SpringCloud等等 ...
- 采用redis生成唯一且随机的订单号
项目描述 最近做的一个项目有这么一个需求:需要生成一个唯一的11位的就餐码(类似于订单号的概念),就餐码的规则是:一共是11位的数字,前面6位是日期比如2019年07月20就是190720,后面五位是 ...
- MySQL中常用到的关于时间的SQL
-- 今天 SELECT DATE_FORMAT(NOW(),'%Y-%m-%d 00:00:00') AS dayStart;SELECT DATE_FORMAT(NOW(),'%Y-%m-%d 2 ...
- golang1.13中重要的新特新
本文索引 语言变化 数字字面量 越界索引报错的完善 工具链改进 GOPROXY GOSUMDB GOPRIVATE 标准库的新功能 判断变量是否为0值 错误处理的革新 Unwrap Is As gol ...