对于当前状态(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