博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ 1085] [SCOI2005] 骑士精神 [ IDA* 搜索 ]
阅读量:4931 次
发布时间:2019-06-11

本文共 2464 字,大约阅读时间需要 8 分钟。

 

题目链接 :

 

题目分析 :

  本题中可能的状态会有 (2^24) * 25 种状态,需要使用优秀的搜索方式和一些优化技巧。

  我使用的是 IDA* 搜索,从小到大枚举步数,每次 DFS 验证在当前枚举的步数之内能否到达目标状态。

  如果不能到达,就枚举下一个步数,重新搜索,即使某些状态在之前的 DFS 中已经搜索过,我们仍然搜索。

  并且在一次 DFS 中,我们不需要判定重复的状态。

  在 IDA* 中,重要的剪枝优化是 估价函数 ,将一些不可能存在可行解的枝条剪掉。

  如果估价函数写得高效,就能有极好的效果。我们写估价函数的原则是,绝对不能剪掉可能存在可行解的枝条。

  因此,在预估需要步数时,应让估计值尽量接近实际步数,但一定不能大于实际需要的步数。

  本题的一个很有效的估价函数是,比较当前状态的黑白骑士与目标状态的黑白骑士有多少不同,我们把这个值作为估价函数值,因为每一步最多将当前状态的一个骑士改变为与目标状态相同。但是应该注意的是,空格所在的格子不要算入其中。

 

代码如下:

  

#include 
#include
#include
#include
#include
#include
 using namespace std; const int MaxStep = 15;const int Dx[8] = { 1, 1, -1, -1, 2, 2, -2, -2}, Dy[8] = { 2, -2, 2, -2, 1, -1, 1, -1}; int Te, Ans; char Str[6]; struct ES{    int num, pos;    bool operator == (const ES &e) const {        return (num == e.num) && (pos == e.pos);    }} S, T; inline bool Inside(int x, int y) {    if (x < 0 || x > 4) return false;    if (y < 0 || y > 4) return false;    return true;} void Print(ES x) {    for (int i = 0; i < 5; ++i) {        for (int j = 0; j < 5; ++j) {            if (x.pos == (i * 5 + j)) printf("*");            else {                if (x.num & (1 << (i * 5 + j))) printf("1");                else printf("0");            }        }        printf("\n");    }} inline int Expect(ES x) {    int Temp, Cnt;    Temp = x.num ^ T.num;    Cnt = 0;    if (x.pos != T.pos) {        if (Temp & (1 << T.pos)) --Cnt;        if (Temp & (1 << x.pos)) --Cnt;    }    while (Temp) {        ++Cnt;        Temp -= Temp & -Temp;    }    return Cnt;} bool DFS(ES Now, int Step, int Limit) {    if (Now == T) return true;    if (Step == Limit) return false;    if (Expect(Now) > Limit - Step) return false;    int x, y, xx, yy;    ES Next;    x = Now.pos / 5; y = Now.pos % 5;    for (int i = 0; i < 8; i++) {        xx = x + Dx[i]; yy = y + Dy[i];        if (!Inside(xx, yy)) continue;        Next = Now;         Next.pos = xx * 5 + yy;        Next.num &= (1 << 25) - 1 - (1 << (xx * 5 + yy));        if (Now.num & (1 << (xx * 5 + yy))) Next.num |= (1 << (x * 5 + y));         if (DFS(Next, Step + 1, Limit)) return true;    }    return false;} int IDAStar(ES S) {    if (S == T) return 0;    for (int i = 1; i <= MaxStep; ++i)         if (DFS(S, 0, i)) return i;    return -1;} int main() {    scanf("%d", &Te);    T.num = 549855; T.pos = 12;    for (int Case = 1; Case <= Te; ++Case) {        S.num = 0;        for (int i = 0; i < 5; ++i) {            scanf("%s", Str);            for (int j = 0; j < 5; ++j) {                if (Str[j] == '1') S.num |= (1 << (i * 5 + j));                if (Str[j] == '*') S.pos = i * 5 + j;            }        }        Ans = IDAStar(S);        printf("%d\n", Ans);    }     return 0;}

 

  

转载于:https://www.cnblogs.com/JoeFan/p/4160896.html

你可能感兴趣的文章
NGINX + PHP-FPM 502
查看>>
mysql数据备份与恢复
查看>>
Openstack API常用命令
查看>>
OpenSSL漏洞凶猛来袭 慧眼恶意代码监测应对有方
查看>>
C语言 喝汽水问题
查看>>
LINUX中搭建DNS服务器,实现正向、反向以及访问不同DNS解析
查看>>
SCCM2012 R2实战系列之十:解决WDS服务无法启动问题(错误1067:进程意外终止)...
查看>>
ubuntu 下安装 mysql
查看>>
关于k-means聚类算法的matlab实现
查看>>
Git分支2
查看>>
一键安装Gitlab后的备份、迁移与恢复
查看>>
因为本人工作繁忙,精力有限,本博客停止更新。有兴趣的博友可以关注我在CSDN上的主博客...
查看>>
SQL server查看触发器是否被禁用
查看>>
[C++基础]在构造函数内部调用构造函数
查看>>
跟随我在oracle学习php(8)
查看>>
Spring 3.1.0 Hibernate 3.0 Eclipse Spring WEB例子
查看>>
UVA-10212 The Last Non-zero Digit. 分解质因子+容斥定理
查看>>
求两个集合的交集,并集,差集
查看>>
Kotlin的语法糖(一)基础篇
查看>>
OkHttp源码分析
查看>>