八数码难题

题目描述

一.广搜:

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

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

我们可以考虑将一个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. tail -f 实时跟踪一个日志文件的输出内容

    tail -f  实时跟踪一个日志文件的输出内容 http://hittyt.iteye.com/blog/1927026 https://blog.csdn.net/mengxianhua/arti ...

  2. [转]jQuery插件写法总结以及面向对象方式写法

    本文转自:http://www.xuanfengge.com/jquery-plug-in-written-summary-and-summary-of-writing-object-oriented ...

  3. thinkphp3.2.3 ueditor1.4.3 图片上传操作,在线删除上传图片功能。

    最近弄一个图片 上传,可是用ueditor 自带的上传,如果不配置的话,上传的目录不在自己的项目中. 在网上找了好多,可是都是底版本的,新版本的还真是找到了一个,ueditor-thinkphp 这个 ...

  4. (转)AIX下修改用户最大进程数

    AIX下修改用户最大进程数 原文:http://blog.csdn.net/feichideche/article/details/39498555 使用AIX时候,切换用户,发现进程一直挂起,查看用 ...

  5. LeetCode 984.不含AAA或BBB的字符串(C++)

    给定两个整数 A 和 B,返回任意字符串 S,要求满足: S 的长度为 A + B,且正好包含 A 个 'a' 字母与 B 个 'b' 字母: 子串 'aaa' 没有出现在 S 中: 子串 'bbb' ...

  6. Spring Cloud学习笔记之微服务架构

    目录 什么是微服务 架构优点 架构的挑战 设计原则 什么是微服务     微服务构架方法是以开发一种小型服务的方式,来开发一个独立的应用系统的.     其中每个小型服务都运行在自己的进程中,并经常采 ...

  7. js的事件冒泡

    先来段代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w ...

  8. HDU5366——The mook jong——dp

    The mook jong Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  9. winfrom C#树勾选等

    AfterCheck /// <summary> /// 树勾选 /// </summary> /// <param name="sender"> ...

  10. Chrome拷贝插件的对比 zeroclipboard和clipboard插件

    1.zeroclipboard插件 实现原理:Zero Clipboard 利用 Flash 进行复制,用了一个透明的 Flash ,让其漂浮在按钮之上,这样其实点击的不是按钮而是 Flash ,也就 ...