八数码难题

题目描述

一.广搜:

首先要考虑用什么存每一个状态

显然每个状态都用一个矩阵存是很麻烦的。

我们可以考虑将一个3*3的矩阵用一个字符串或long long 存。

每次扩展时再转化为矩阵。

另外一个问题是判重,对于已经搜过的状态,就不再扩展了。

10^9次方的bool数组会爆空间

可以考虑用hash

或者STL的map或set

//map   洛谷 8964ms
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
map<long long ,long long> m;
long long s,que[],head=,tail=;
long long c[][];
long long zx[]={,,,,-},
zy[]={,,-,,};
int main()
{
scanf("%lld",&s);
m[s]=;
que[head]=s;
while(head<=tail) //广搜
{
int x,y;
long long u=que[head++]; //取出队首元素
long long uu=u;
if(u==) break;
for(int i=;i<=;i++) //将long long型转化为矩阵
for(int j=;j<=;j++)
{
c[i][j]=uu%;
if(c[i][j]==){ //标记空格
x=i;
y=j;
}
uu/=;
}
for(int i=;i<=;i++)
{
long long xx=x+zx[i],yy=y+zy[i]; //向四个方向搜索
if(<=xx&&xx<=&&<=yy&&yy<=)
{
swap(c[x][y],c[xx][yy]);
long long l=;
for(int j=;j>=;j--)
for(int k=;k>=;k--)
l=l*+c[j][k]; //将扩展状态转化为长整形
map < long long ,long long > :: iterator it = m.find(l) ; //判重 map中的find函数用于寻找象所对应的原象(键值),若查找失败,返回最后一个键值位置
if(it==m.end()){
m[l]=m[u]+;
que[++tail]=l;
}
swap(c[x][y],c[xx][yy]);
}
}
}
printf("%lld\n",m[]);
return ;
}
//hash   洛谷 1080ms
#pragma GCC optimize(3)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MOD=;
long long s,que[],time[],head=,tail=;
long long c[][];
long long zx[]={,,,,-},
zy[]={,,-,,};
bool hashnum[];
inline bool hash(long long s)
{
long long h=,i=;
while(s)
{
i++;
long long k=s%;
s/=;
h=(h*i*+k)%MOD;
}
if(!hashnum[h]){
hashnum[h]=;
return ;
}
else return ;
}
int main()
{
scanf("%lld",&s);
que[head]=s;
while(head<=tail)
{
int x,y;
long long u=que[head++];
long long uu=u;if(u==) break;
for(register int i=;i<=;i++)
for(register int j=;j<=;j++)
{
c[i][j]=uu%;
if(c[i][j]==){
x=i;
y=j;
}
uu/=;
}
for(register int i=;i<=;i++)
{
long long xx=x+zx[i],yy=y+zy[i];
if(<=xx&&xx<=&&<=yy&&yy<=)
{
swap(c[x][y],c[xx][yy]);
long long l=;
for(int j=;j>=;j--)
for(int k=;k>=;k--)
l=l*+c[j][k];
if(hash(l)){
que[++tail]=l;
time[tail]=time[head-]+;
}
swap(c[x][y],c[xx][yy]);
}
}
}
printf("%lld\n",time[head-]);
return ;
}

二、启发式搜索

估价函数:

close[i]=time[i]+cym[i]

time[i]是搜到当前状态已经用的时间

cym[i]表示每个数字到目标状态的曼哈顿距离之和/2

可以看出,close[i]是小于实际步数的,所以搜起来效率高些

//启发式搜索 420ms
#pragma GCC optimize(3)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int MOD=;
long long s,num;
long long data[];
int time[];
int close[];
struct cmp
{
bool operator()(int a,int b)
{
return close[a]>close[b];
}
};
priority_queue<int,vector<int>,cmp> que;
long long c[][];
long long zx[]={,,,,-},
zy[]={,,-,,};
bool hashnum[];
inline bool hash(long long s)
{
long long h=,i=;
while(s)
{
i++;
long long k=s%;
s/=;
h=(h*i*+k)%MOD;
}
if(!hashnum[h]){
hashnum[h]=;
return ;
}
else return ;
}
int de[][]={{,},{,},{,},{,},{,},{,},{,},{,},{,}};
inline int cym(long long tt) //个位数字的笛卡尔距离之和
{
int nn[][];
for(register int i=;i<;i++)
for(register int j=;j<;j++)
{
nn[-i][-j]=tt%;
tt/=;
}
int mark=;
for(register int i=;i<=;i++)
for(register int j=;j<=;j++)
mark+=abs(i-de[nn[i][j]][])+abs(j-de[nn[i][j]][]);
return mark>>1;
}
int main()
{
scanf("%lld",&s);
data[++num]=s;
close[num]=cym(s);
que.push(num);
int u;
while(!que.empty())
{
int x,y;
u=que.top(); //每次取估价最小的元素
que.pop();
long long uu=data[u];if(uu==) break;
for(register int i=;i<=;i++)
for(register int j=;j<=;j++)
{
c[i][j]=uu%;
if(c[i][j]==){
x=i;
y=j;
}
uu/=;
}
for(register int i=;i<=;i++)
{
long long xx=x+zx[i],yy=y+zy[i];
if(<=xx&&xx<=&&<=yy&&yy<=)
{
swap(c[x][y],c[xx][yy]);
long long l=;
for(int j=;j>=;j--)
for(int k=;k>=;k--)
l=l*+c[j][k];
if(hash(l)){
data[++num]=l;
time[num]=time[u]+;
close[num]=cym(l)+time[num]; //估价
que.push(num);
}
swap(c[x][y],c[xx][yy]);
}
}
}
printf("%lld\n",time[u]);
return ;
}

【洛谷P1379】八数码难题(广搜、A*)的更多相关文章

  1. 洛谷 P1379 八数码难题 解题报告

    P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...

  2. 洛谷——P1379 八数码难题

    P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...

  3. 洛谷P1379八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...

  4. 洛谷 P1379 八数码难题 Label:判重&&bfs

    特别声明:紫书上抄来的代码,详见P198 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给 ...

  5. 洛谷 P1379 八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了 ...

  6. 洛谷 - P1379 - 八数码难题 - bfs

    https://www.luogu.org/problemnew/show/P1379 #include <bits/stdc++.h> using namespace std; #def ...

  7. 洛谷—— P1379 八数码难题

    https://daniu.luogu.org/problem/show?pid=1379 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示 ...

  8. 洛谷 P1379 八数码难题 题解

    我个人感觉就是一道bfs的变形,还是对bfs掌握不好的人有一定难度. 本题思路: 大体上用bfs搜,用map来去重,在这里只需要一个队列,因为需要较少步数达到的状态一定在步数较多的状态之前入队列. # ...

  9. 洛谷P1379 八数码难题

    传送门 1.先用dfs枚举9!的全排列,存到hash数组里(类似离散化),因为顺序枚举,就不需要排序了 2.朴素bfs,判重就用二分找hash:如果发现当前状态=要求状态,输出步数结束程序 上代码 # ...

  10. 洛谷 P1379 八数码难题(map && 双向bfs)

    题目传送门 解题思路: 一道bfs,本题最难的一点就是如何储存已经被访问过的状态,如果直接开一个bool数组,空间肯定会炸,所以我们要用另一个数据结构存,STL大法好,用map来存,直接AC. AC代 ...

随机推荐

  1. java多线程(一)

    一.进程,线程,并发,并行 1.1 进程和线程的区别       进程是指:一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运 ...

  2. Turing Year 2012

    Turing LectureFrom cryptanalysis to cognitive neuroscience - a hidden legacy of Alan Turinghttp://co ...

  3. DRF之权限认证频率组建

    认证组件 很久很久以前,Web站点只是作为浏览服务器资源(数据)和其他资源的工具,甚少有什么用户交互之类的烦人的事情需要处理,所以,Web站点的开发这根本不关心什么人在什么时候访问了什么资源,不需要记 ...

  4. Oracle SQL Tuning Advisor 测试

    如果面对一个需要优化的SQL语句,没有很好的想法,可以先试试Oracle的SQL Tuning Advisor. SQL> select * from v$version; BANNER --- ...

  5. #define\const\inline的区别与联系

    总结: const用于代替#define一个固定的值,inline用于代替#define一个函数.是#define的升级版,为了消除#define的缺陷. 参考内容:http://www.cnblog ...

  6. stm32 窗口看门狗学习(一)

    什么是窗口看门狗? 1)独立看门狗                限制喂狗时间在0-x内,x由相关寄存器决定.喂狗的时间不能过晚. 2)窗口看门狗               之所以称为窗口就是因为其 ...

  7. linux程序分析工具介绍(二)—-ldd,nm

    本文要介绍的ldd和nm是linux下,两个用来分析程序很实用的工具.ldd是用来分析程序运行时需要依赖的动态库的工具:nm是用来查看指定程序中的符号表相关内容的工具.下面通过例子,分别来介绍一下这两 ...

  8. 处理IIS 255错误,和相关信息

    不知不觉已经注册博客一年多了,当初看见博客园的大神,自己也想像他们一样多写一些有用的,结果,,,不言而喻.在这里又感慨了一下,进入正题了.. 最近在公司服务器接触的比较多, 遇到了一个255 的问题 ...

  9. 学习路线 roadmap

    我的学习路线为HTML > CSS > Javsscript:Javascript是前端一切学习的基础.HTML和css一起学习. JavaScript基础: Js基础教程.js内置对象常 ...

  10. 初识ImageSwither

    imageswitcher继承自viewswitcher,使用ImageSwither只需要两步: 1.为ImageSwither提供一个ViewFactory,该ViewFactory生成的View ...