8数码问题-搜索-双向BFS/A*算法

本文介绍了8数码问题的解决方案,包括单向BFS、双向BFS和A*算法。双向BFS能有效减少搜索时间,而A*算法利用估价函数加快寻找最短路径。文章提供了算法思路及部分代码示例,并讨论了估值函数在8数码问题中的应用。
摘要由CSDN通过智能技术生成

1849: 【基础算法】8数码问题版本一

题目描述
在一个3*3的九宫格棋盘里,放有8个数码,数码的数字分别是1~8等8个数字。可以通过在九宫格里平移数码来改变状态。数码在任何情况下都不能离开棋盘。给出8个数码的初始状态(没放数码的空格用0表示)和目标状态,问从初始状态到目标状态,最少需要经过多少次移动操作。

例如,初始状态为:

2 6 4
1 3 7
0 5 8

目标状态是:

8 1 5
7 3 6
4 0 2

最少的移动步数为31步。
输入
第1行:9个空格分开的整数,表示初始状态

第2行:9个空格分开的整数,表示目标状态

整数都在0~8范围内,且不重复

输出
第1行:1个整数,表示从初始状态到目标状态的最少移动步数。如果无解,输出-1

样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2
样例输出
31

解一:单向BFS
好慢的吧

解二:双向BFS
模型:当知道开始状态和结束状态,需要求一条从s到t的一条最短路径
当单向搜索的时候,搜索的隐式树呈爆炸式增长,好恐怖的。。
不过如果双向搜,会避免掉很多,时间复杂度由K^L变为2*(K^(L/2)),将大大减少。(K为度数,L为层数)
比如说单向是一个大三角,双向就是大三角中的一个小“菱形”(还是比较像..)

实现的时候用一个队列即可,先把s和t压入queue,挨着广搜。由于是广搜,s和t的子状态都是“一块一块的”,不会混在一起。

代码比较丑:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAXN 9
#define MAXKT 362880
struct node{
    char s[MAXN+10];
    int step;
    bool flag;
    int blank;

};
int pos,steps[MAXKT+10],w[MAXN+10];
int dir[4+5]={
  1,-1,3,-3};
bool vis[2+5][MAXKT+10];
char s[MAXN+10],t[MAXN+10];
void read()
{
    int a;
    for(int i=0;i<9;i++){
        scanf("%d",&a);
        s[i]=a+'0';
    }
    for(int i=0;i<9;i++){
        scanf("%d",&a);
        t[i]=a+'0';
    }
    w[8]=0; w[7]=1;
    for(int i=6;i>=0;i--) w[i]=w[i+1]*(8-i);
}
int kangtuo(char *x)
{
    int ret=0;
    for(int i=0;i<9;i++){
        if(x[i]=='0'){
            pos=i; continue;
        }
        for(int j=i+1;j<9;j++)
            if(x[j]<x[i])
                ret+=w[i];
    }
    return ret;
}
void double_BFS()
{
    queue<node> que;
    int num=kangtuo(s);
    node start; memcpy(start.s,s,sizeof s);start.step=0,start.flag=0,start.blank=pos;
    que.push(start);
    vis[0][num]=true;
    num=kangtuo(t);
    node end; memcpy(end.s,t,sizeof s);end.step=0,end.flag=1,end.blank=pos;
    que.push(end);
    vis[1][num]=true;

    while(!que.empty()){
        node cur=que.front(); que.pop();
        node next;
        num=kangtuo(cur.s);
        char state[MAXN+10];
        memcpy(state,cur.s,sizeof cur.s);
        for(int i=0;i<4;i++){
            int newpos=cur.blank+dir[i];
            if(newpos>=0&&newpos<9&&((newpos/3==cur.blank/3)||(newpos%3==cur.blank%3))){
                //同一列||同一行
                swap(state[cur.blank],state[newpos]);
                int newnum=kangtuo(state);
                if(vis[!cur.flag][newnum]){
                    printf("%d\n",cur.step+steps[newnum]+1);
                    return ;
                }
                else if(!vis[cur.flag][newnum]){
                    vis[cur.flag][newnum]=true;
                    steps[newnum]=cur.step+1;
  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值