八数码难题

题目描述

一.广搜:

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

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

我们可以考虑将一个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. 在IE8下background-image不显示的解决方法

    刚写一个页面,在chrome,FF里调试完后,忽然想起ie来,放到Ie里其它还好了,但是有个背景图片显示不出来. 调试N遍后,只好上stackoverflow去找一下,果然找到了. 最初是这样写的: ...

  2. [转]25个HTML5和JavaScript游戏引擎库

    本文转自:http://www.open-open.com/news/view/27c6ed 1. The GMP JavaScript Game Engine GMP是一个基于精灵2-D游戏,它可以 ...

  3. C++(SOCKET)简单爬虫制作

    先给出代码:(我使用的是VS编译器,需要在项目->project属性-> #include <iostream> #include <stdio.h> #inclu ...

  4. Linux证书登录,禁用密码

    如果验证成功的话就可以关闭密码登陆方式了, 编辑/etc/ssh/sshd_config, 将PasswordAuthentication改为no, ChallengeResponseAuthenti ...

  5. Linux下jdk下载

    wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-co ...

  6. 【Ionic】---Using Local Notifications In Your Ionic Framework App

    Using Local Notifications In Your Ionic Framework App 配置好ng-cordova先 <script src="lib/ngCord ...

  7. C#中 计时器用法 运行时间

    有时候我们会需要计算某段代码运行的时间 比如一个sql查询,记录一段代码所花费的时间等等代码如下: System.Diagnostics.Stopwatch watch = new System.Di ...

  8. Win2D 官方文章系列翻译 - 调整控件分辨率

    本文为个人博客备份文章,原文地址: http://validvoid.net/win2d-choosing-control-resolution/ 本文旨在讲解如何配置 Win2D XAML 控件使用 ...

  9. hibernate课程 初探一对多映射1-1 课程简介

    hibernate 常见映射类型 one-to-many many-to-one one-to-one many-to-many

  10. 《Head First 设计模式》之代理模式

    代理模式(Proxy):控制对象访问 ——为另一个对象提供一个替身或占位符来访问这个对象. 要点: 代理模式有许多变体,如:缓存代理.同步代理.防火墙代理和写入时复制代理 代理在结构上类似装饰者,但目 ...