15Puzzle 强行A*求解 C++

本文介绍了使用A*算法解决15Puzzle问题的方法,通过调整启发函数参数(如21:11和17:10)来优化求解过程。在特定情况下,这些参数设置可以保证在70步内找到最优解。同时,文章讨论了启发函数的玄学魔改,包括哈密顿距离和线性冲突的结合。还提供了15Puzzle的C++模拟器源代码,支持在Windows和C4droid环境下编译运行,允许用户进行移动、打乱和求解操作。
摘要由CSDN通过智能技术生成

对于当前状态(f,p)做了启发函数,由U=depth*factor1+getU(f,p)*factor2;得出节点的U,始终先搜索U较小的情况

虽说老老实实 U=depth+HL(f,p) (HL为曼哈顿距离+线性冲突*2) 可以理论上比较容易地证明得出最优解,而且也能对付一些比较简单的情况,然而我并没有这么做, 在一系列疯狂凑参数+瞎几把优化后,竟然得出了非常实用的伪劣A*解

factor根据需求可调整为
21:11(求最优解,在70步内未发现反例,建议使用) ,但一些70步以上的case可以说是GG了,在luogu上我发了个个人题,放了7个随机中前30%难(按我的代码运行时间排)的case,和1个偶然找到的虽然只有55步,但可以让基于哈密顿距离的启发函数表现很差的case, 还有1个70步case (基本上由随机+向步数增加方向移动是到不了70步的),表现是(用21:11), 7.52ms/181.45MB, 耗时最长为55步的case 2.6s.
2:1 且修改fmp为0,2,4,6,2,4,6,8…, (严格求最优解,效率感人)
17:10 (求大部分情况的最优解,对于有较小可能性多2步)
3:2 (很快速求解,目前没发现超过600ms的情况,可能会多2-6步)

目前我的方式是 21:11达到限制后转 17:10
对于15 14 9 13 11 10 0 12 7 6 5 8 3 1 2 4, 17:10的结果是75,不知道对不对。

也可以在hashset done 中加上步数信息以回溯得知具体解。

也许你会想:A*的内存不会炸?
那我只能表示,用int64存一个状态足矣

还有,启发函数用啥?
玄学魔改哈密顿距离+伪劣版线性冲突你值得拥有

下面是15Puzzle模拟器并加上了求解功能:
可在Windows或C4droid 由GCC编译 (C++11 以上)

操作: WSAD/2468移动,0/r随机打乱,1/h求解(只有长度),3/i开启输入

#define WINDOWS
#ifdef WINDOWS
#include <windows.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <conio.h>
#include <unordered_set>
#include <queue>
#include <functional>

/*
   3 11 6 0 2 1 9 8 4 7 14 5 15 10 12 13  55
   15 14 9 13 11 10 0 12 7 6 5 8 3 1 2 4  75??
*/
   
using namespace std;

typedef unsigned long long U64;

const U64* base=[]() {
   
	U64 *b=new U64[16] {
   15};
	for(int i=1; i<16; ++i) {
   
		b[i]=(b[i-1]<<4);
	}
	return b;
}();

const U64 *rbase=[]() {
   
	U64 *rb=new U64[16];
	for(int i=0; i<16; ++i) rb[i]=~base[i];
	return rb;
}();

U64 ac=0xfedcba9876543210llu;
const char U_=0,D_=1,L_=2,R_=3,RANDF=17,NEXTI=18,IMPORT=19,ILLACT=-1;

#define REV(DR) ((DR)^1)

#define U_ABLE(P) ((P)&12)
#define U_P(P) ((P)-4)
#define D_ABLE(P) ((P)<12)
#define D_P(P) ((P)+4)
#define L_ABLE(P) ((P&3))
#define L_P(P) ((P)-1)
#define R_ABLE(P) (~(P)&3)
#define R_P(P) ((P)+1)

#define up(F,P) ((rbase[P]|(F<<16))&F|base[P-4])
#define down(F,P) ((rbase[P]|(F>>16))&F|base[P+4])
#define left(F,P) ((rbase[P]|(F<<4))&F|base[P-1])
#define right(F,P) ((rbase[P]|(F>>4))&F|base[P+1])

const int fmp[4][4]= {
   {
   0,2,4,7},
	{
   2,4,6,10},
	{
   4,6,9,12},
	{
   7,10,12,15}
};

int factor1=21,factor2=11;
int next_factor1=17, next_factor2=10;
const size_t MAXSIZE=20000000;


void output(U64 o) {
   
	for(int i=0; i<4; ++i) {
   
		for(int j=0
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值