【洛谷P1379】八数码难题(广搜、A*)
八数码难题
一.广搜:
首先要考虑用什么存每一个状态
显然每个状态都用一个矩阵存是很麻烦的。
我们可以考虑将一个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*)的更多相关文章
- 洛谷 P1379 八数码难题 解题报告
P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...
- 洛谷——P1379 八数码难题
P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...
- 洛谷P1379八数码难题
题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...
- 洛谷 P1379 八数码难题 Label:判重&&bfs
特别声明:紫书上抄来的代码,详见P198 题目描述 在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 ...
- 洛谷—— P1379 八数码难题
https://daniu.luogu.org/problem/show?pid=1379 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示 ...
- 洛谷 P1379 八数码难题 题解
我个人感觉就是一道bfs的变形,还是对bfs掌握不好的人有一定难度. 本题思路: 大体上用bfs搜,用map来去重,在这里只需要一个队列,因为需要较少步数达到的状态一定在步数较多的状态之前入队列. # ...
- 洛谷P1379 八数码难题
传送门 1.先用dfs枚举9!的全排列,存到hash数组里(类似离散化),因为顺序枚举,就不需要排序了 2.朴素bfs,判重就用二分找hash:如果发现当前状态=要求状态,输出步数结束程序 上代码 # ...
- 洛谷 P1379 八数码难题(map && 双向bfs)
题目传送门 解题思路: 一道bfs,本题最难的一点就是如何储存已经被访问过的状态,如果直接开一个bool数组,空间肯定会炸,所以我们要用另一个数据结构存,STL大法好,用map来存,直接AC. AC代 ...
随机推荐
- 使用Ext 创建树
ext使用的是ext3.4.0版本 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> < ...
- python get_dummies与cut离散化数据
- Murano Weekly Meeting 2015.09.22
Meeting time: 2015.September.22th 1:00~2:00 Chairperson: Serg Melikyan, PTL from Mirantis Meeting s ...
- (转)ssh-keygen 中文手册
ssh-keygen 中文手册 原文:http://www.jinbuguo.com/openssh/ssh-keygen.html 实例:http://blog.csdn.net/yl_1314/a ...
- ThreadFactory
在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:只要当前JVM实例中尚存在任何一个非守护 ...
- tck/tl 以及expect脚本
最近有用到,利用expcet脚本自动登录到远程服务器并提权执行脚本. 搜集的知识如下: tcl/tk参考——列表操作lindex expect脚本解释 代码如下 #!/usr/bin/expect - ...
- iOS 警告收集快速消除
1.ld: warning: directory not found for option 去掉警告的方法 工程老是提示ld: warning: directory not found for opt ...
- 如何绘制ER图
先画出多个实体(用长方形表示),然后是联系类型(菱形),和属性(椭圆).
- Hibernate课程 初探一对多映射4-3 测试--信息查询
建立双向一对多关系,既可以由一方查询多方信息,同样可以由多方查询一方信息 demo: //查询学生所在班级 public static void showGidByStudent(){ Session ...
- css属性(常用属性整理)
摘要:本文是我在学习前端的过程中整理的一些常用css属性,部分是css3新增的,因能力有限,文中如有错误,欢迎提出,我会及时修改.希望对大家有帮助! CSS属性 CSS属性 1 1. css颜色属性 ...