[luogu]P1379 八数码难题[广度优先搜索]
八数码难题
——!x^n+y^n=z^n
我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…)
各位如果想用IDA*的可以看看这位大佬的这篇文章:
http://www.cnblogs.com/ZYBGMZL/p/6852733.html
接下来是我的方法,用luogu的跑了最慢是200ms,感觉还行把。
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入输出格式
输入格式:
输入初试状态,一行九个数字,空格用0表示
输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输入输出样例
输入样例#1:
283104765
输出样例#1:
4
因为这是要最优解且保证数据有解,于是就想到了BFS。
然而这个过程是有许多障碍的,要怎样检验自己的状态是否为解,还有判重的操作,如果你没有判重,TLE即在眼前…
所以我们可以想到压缩状态!当然如果用二进制难免有点力不从心,那我们干脆存成整数不就行了?但是可能你会发现,会有前导零的情况,怎么办?
这时候其实可以在状态前加一个1,在int型中还是过得去的。
那判重怎么搞?注意到这只有9!种状态。
想到什么?康托尔展开!对于0~8的全排列,
012345678 的字典序是1,如果让你手动操作我想没什么问题,那怎么让计算机做这件事?
对于 (a(n-1) a(n-2)L a(0))的字典序计算方法为:
Σ(ci*i!)ci为当前未出现的比ai小的数的个数。
既然这样,我们就能把状态一一存下来了,交换的话很简单,读者手动操作即可发现规律。
简单说明之后附上代码参考一下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 400000
//阶乘?我当然打表啦。
]={,,,,,,,,,};
//状态
struct sjs{
int num;
int pos;
}state[maxn];
//队列
struct _757{
int time;
int now;
int fd;
}qu[maxn];
];
//判重
bool rep[maxn];
int head,tail;
//特殊嗜好???
namespace lys{
//快速幂
int fpow(int p){
,;
){
) res*=base;
base*=base;
p>>=;
}
return res;
}
//计算cantor
int cantor(int num){
,pos,res=;
int x=num;
memset(cto,,sizeof cto);
){
cto[i]=num%;
) pos=i;
num/=;
i++;
}
int j,cal;
;i>=;i--){
cal=;
;j>i;j--){
if(cto[j]<cto[i]) cal++;
}
res+=(cto[i]-cal)*fac[i];
}
state[res+].num=x;
state[res+].pos=pos;
;
}
//判断是否能移动
bool chk(int pos,int i){
switch(i){
:) return true ; return false ;
:) return true ; return false ;
:||pos==||pos==) return false ; return true ;
:||pos==||pos==) return false ; return true ;
}
}
int bfs(){
,i,st,ch,fp,x,num;
do{
st=qu[head].now;
fp=fpow(state[st].pos);
num=state[st].num;
;i<=;i++){
if(chk(state[st].pos,i)){
switch(i){
:
x=(num/(fp*))%;
ch=num-x*fp*+x*fp;
x=cantor(ch);
qu[++tail].now=x;
qu[tail].time=(qu[head].time+);
qu[tail].fd=head;
//目标态,觉得不这样写也行,直接用num比较
){
return qu[tail].time;
}
if(rep[x]) tail--;
else rep[x]=true ;
break ;
:
x=(num/(fp/))%;
ch=num-x*fp/+x*fp;
x=cantor(ch);
qu[++tail].now=x;
qu[tail].time=(qu[head].time+);
qu[tail].fd=head;
){
return qu[tail].time;
}
if(rep[x]) tail--;
else rep[x]=true ;
break ;
:
x=(num/(fp*))%;
ch=num+x*fp-x*fp*;
x=cantor(ch);
qu[++tail].now=x;
qu[tail].time=(qu[head].time+);
qu[tail].fd=head;
){
return qu[tail].time;
}
if(rep[x]) tail--;
else rep[x]=true ;
break ;
:
x=(num/(fp/))%;
ch=num+x*fp-x*fp/;
x=cantor(ch);
qu[++tail].now=x;
qu[tail].time=(qu[head].time+);
qu[tail].fd=head;
){
return qu[tail].time;
}
if(rep[x]) tail--;
else rep[x]=true ;
break ;
}
}
}
head++;
}while(head<=tail);
}
int main(){
int i,j;
char c;
;
;i<=;i++){
;j<=;j++){
c=getchar();
') c=getchar();
st=st*+c-';
}
}
//初始状态
+st);
qu[++head].now=r;
qu[head].time=;
rep[r]=true ;
tail=;
printf("%d\n",bfs());
;
}
}
int main(){
lys::main();
;
}
[luogu]P1379 八数码难题[广度优先搜索]的更多相关文章
- luogu P1379 八数码难题
题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了 ...
- luogu P1379 八数码难题(A*算法入门详细讲解)
代码实现细节 #include<cstdio> #include<cstring> #include<iostream> using namespace std; ...
- 洛谷 P1379 八数码难题 解题报告
P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...
- 洛谷——P1379 八数码难题
P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...
- 洛谷P1379八数码难题
题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...
- codevs1225八数码难题(搜索·)
1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description Yours和zero在研究A*启 ...
- 洛谷—— P1379 八数码难题
https://daniu.luogu.org/problem/show?pid=1379 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示 ...
- 洛谷 P1379 八数码难题
题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了 ...
- 洛谷 - P1379 - 八数码难题 - bfs
https://www.luogu.org/problemnew/show/P1379 #include <bits/stdc++.h> using namespace std; #def ...
随机推荐
- mysql安装报错
一: -- MySQL 5.5.22Warning: Bison executable not found in PATH-- Configuring done-- Generating done-- ...
- 在chrome下鼠标拖动层变文本形状的问题
学JQ也有一段时间了,想自己写个鼠标拖动层移动的效果(很简单,只是为了练习而已)于是就写下了下面的代码 <!DOCTYPE html> <html> <head> ...
- 织梦DEDECMS中的默认文件夹的名称怎么修改呢?
1.首先找到系统配置文件,一般此文件会存放在Include目录下,文件名称为:common.inc.php. 2.打开common.inc.php,以修改模板目录templets为例, ...
- [附录]Discuz X2.5程序模块source功能处理目录注释
/source/admincp后台管理 /source/admincp/cloud云平台项目 /source/admincp/menu后台扩展菜单目录 /source/admincp/moderate ...
- 【MyBatis源码解析】MyBatis一二级缓存
MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...
- vue init webpack-simple project 报错处理(connect ETIMEDOUT 192.30.253.112)
Failed to download repo vuejs-templates/webpack-simple: connect ETIMEDOUT 192.30.253.113:443 Failed ...
- Vue.js组件之间的通信
导语:组件之间的关系不外乎两种, 父子组件和非父子组件,本文将对两类组件之间的通信方式进行详细阐述. 父子组件间的通信 通信方式1(单向绑定): Props down, Events up (建议使用 ...
- jmeter 实现DB数据与接口数据的匹配校验
前言:接口出参数据与DB数据结合校验,使校验力度更准确~ jmeter自带插件JDBC Request Sampler 这个Sampler可以向数据库发送一个jdbc请求(sql语句),并获取返回的数 ...
- 关于MyEclipse修改项目名称后,部署到tomcat显示旧的项目名称
问题:用Myeclipse部署项目的时候, 出现部署到tomcat下的项目是之前的项目,而不是当前的项目. 解决方案:工程名->右键->Properties->MyEcl ...
- 虚拟桌面 VDI
什么是VDI(Virtual Desktop Infrastructure): 通过对于本企业的服务器进行整合,使用VMware进行虚拟机部署,利用服务器资源,实现由一个物理机实现多个虚拟机,解决资源 ...