隐式图的搜索问题

一、实验内容

编写九宫重排问题的启发式搜索(A*算法)求解程序。

在3х3组成的九宫棋盘上,放置数码为1~8的8个棋子,棋盘中留有一个空格,空格周围的棋子可以移动到空格中,从而改变棋盘的布局。根据给定初始布局和目标布局,编程给出一个最优的走法序列。输出每个状态的棋盘。

测试数据:初始状态:123456780  目标状态:012345678

【输入格式】
     输入包含三行,每行3各整数,分别为0-8这九个数字,以空格符号隔开,标识问题的初始状态。0表示空格,例如:
2 0 3

1 8 4

7 6 5

二、设计思路

一)A*算法描述:

* 初始化open和close;
* 将起点加入open中,并设置优先级为0(优先级最高);
* 如果open不为空,则从open中选取优先级最高的节点n:
    * 如果节点n为终点,则:
        * 从终点开始逐步追踪parent节点,一直达到起点;
        * 返回找到的结果路径,算法结束;
    * 如果节点n不是终点,则:
        * 将节点n从open中删除,并加入close中;
        * 遍历节点n所有的邻近节点:
            * 如果邻近节点m在close中,则:
                * 跳过,选取下一个邻近节点
            * 如果邻近节点在open中,则:
                * 则比较gcost是否比原来更小,如果更小则更新其父节点
            * 如果邻近节点m也不在open中,则:
                * 设置节点m的parent为节点n
                * 计算节点m的优先级
                * 将节点m加入open中

二)数据结构

class Node 

节点类,元素包括:

用二维数组表示的节点,当前节点的先辈节点和扩展节点

class A_algorithm

A*算法,私有数据成员包括:

初始节点,目标节点,扩展节点,可扩展节点的个数

A_algorithm(Node* S0, Node* Sg); 构造函数
int IsSg(Node* S) { return memcmp(&S->Node, &Sg.Node, sizeof(int) * 9); }判断是否是目标状态
int Nextnode(Node* S);下一个可行的节点
void algorithm();A*算法
void PrintPath(Node* head);打印路径
void FreeCLOSED(Node* CLOSED);释放close表

三)源码

Astar_search.cpp

#include"A_algorithm.h"

int main() 
{  
    Node S0; 
    S0.next = NULL;
    S0.parent = NULL;
    Node Sg;
    Sg.next = NULL;
    Sg.parent = NULL;

    //初始化输入输出
    cout<<"Please input initial Node:"<<endl;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            cin >> S0.Node[i][j];
    cout<<"Please input goal Node:"<<endl;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            cin >> Sg.Node[i][j];
    
    //Node S0 = { {{2, 8, 3}, {1, 6, 4}, {7, 0, 5}}, 0, NULL };//初始化初始节点
    //Node Sg = { {{1, 2, 3}, {7, 8, 4}, {0, 6, 5}}, 0, NULL };//初始化目标节点
    cout << endl << "SearchPath: " << endl << endl;
    A_algorithm(&S0, &Sg).algorithm();
    return 0;
}

A_algorithm.h

#pragma once
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#include <memory.h>
using namespace std;

class Node                  //节点类
{
public:
    int Node[3][3];         //每个节点用一个二维数组表示
    class Node* parent;     //节点的先辈节点
    class Node* next;       //节点的扩展节点
};

class A_algorithm
{
public:
    A_algorithm(Node* S0, Node* Sg);        //构造函数
    int IsSg(Node* S) { return memcmp(&S->Node, &Sg.Node, sizeof(int) * 9); } //判断是否是目标状态
    int Nextnode(Node* S);                  // 下一个可行的节点
    void algorithm();                       // A*算法
    void PrintPath(Node* head);             // 打印路径
    void FreeCLOSED(Node* CLOSED);          // 释放close表
private:
    Node S0;                                //初始节点
    Node Sg;                                //目标节点
    int Nextnum;                            //可扩展节点数
    Node next[4];                           //扩展节点
};

A_algorithm.cpp

#pragma once
#include "A_algorithm.h"

//sort函数的排序规则,返回估价函数值最大的节点
bool cmp(const Node& s1, const Node& s2)
{
    int gx1 = 0, gx2 = 0;   //gx为从初始节点到该节点已经付出的代价
    int hx1 = 0, hx2 = 0;   //hx为该节点到达目的节点的接近程度估计值
    const Node* ptr1 = &s1;
    const Node* ptr2 = &s2;
    int Node[3][3] = {
                    {1,2,3},
                    {8,0,4},
                    {7,6,5} };
    
    while (ptr1 != NULL)
    {
        gx1 += 1;
        ptr1 = ptr1->parent;
    }
    while (ptr2 != NULL)
    {
        gx2 += 1;
        ptr2 = ptr2->parent;
    }
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            if (s1.Node[i][j] != Node[i][j])
                hx1 += 1;
            if (s2.Node[i][j] != Node[i][j])
                hx2 += 1;
        }
    }
    return (gx1 + hx1) > (gx2 + hx2);
}

A_algorithm::A_algorithm(Node* S0, Node* Sg)
{
    //初始化S0节点的值,先辈结点和扩展结点为空
    memcpy(&this->S0.Node, &S0->Node, sizeof(int) * 9);
    this->S0.parent = NULL;
    this->S0.next = NULL;
    //初始化Sg节点的值,先辈结点和扩展结点为空
    memcpy(&this->Sg.Node, &Sg->Node, sizeof(int) * 9);
    this->Sg.parent = NULL;
    this->Sg.next = NULL;
}

//返回可扩展节点的个数
int A_algorithm::Nextnode(Node* S)
{
    Nextnum = 0;
    int posi, posj;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            if (S->Node[i][j] == 0)
            {
                posi = i; posj = j;//定位到S节点的空位置处
                break;
            }
    if (posi - 1 >= 0) //向上扩展
    {
        Node up = *S;
        up.Node[posi][posj] = up.Node[posi - 1][posj];
        up.Node[posi - 1][posj] = 0;
        next[Nextnum] = up;
        next[Nextnum].parent = S;
        Nextnum++;
    }
    if (posi + 1 <= 2) //向下扩展
    {
        Node down = *S;
        down.Node[posi][posj] = down.Node[posi + 1][posj];
        down.Node[posi + 1][posj] = 0;
        next[Nextnum] = down;
        next[Nextnum].parent = S;
        Nextnum++;
    }
    if (posj - 1 >= 0) //向左扩展
    {
        Node left = *S;
        left.Node[posi][posj] = left.Node[posi][posj - 1];
        left.Node[posi][posj - 1] = 0;
        next[Nextnum] = left;
        next[Nextnum].parent = S;
        Nextnum++;
    }
    if (posj + 1 <= 2) //向右扩展
    {
        Node right = *S;
        right.Node[posi][posj] = right.Node[posi][posj + 1];
        right.Node[posi][posj + 1] = 0;
        next[Nextnum] = right;
        next[Nextnum].parent = S;
        Nextnum++;
    }
    return Nextnum;
}

void A_algorithm::algorithm()
{
    vector<Node> OPEN;                  //生成一个node类型的数组OPEN
    Node* CLOSED = new Node;
    Node* current = CLOSED;
    Node* N;
    OPEN.push_back(S0);                 //把初始节点S0放入OPEN表
    while (!OPEN.empty())
    {
        N = new Node;
        *N = OPEN[OPEN.size() - 1];     //指向最后一个节点
        OPEN.pop_back();                //移出OPEN表的最后一个节点
        current->next = N;              //把N放入CLOSED表中
        current = current->next;
        if (IsSg(N) == 0)               //如果目标节点Sg=N,则搜索成功,结束
        {   
            PrintPath(N);               //打印出N
            FreeCLOSED(CLOSED);         //释放CLOSED表
            return;
        }
        int Nextnum = Nextnode(N);      //扩展N节点,并取N节点的可扩展节点数
        if (Nextnum == 0)               //如果N不可扩展则继续
            continue;
        else
            for (int i = 0; i < Nextnum; i++)
                OPEN.push_back(next[i]);
        sort(OPEN.begin(), OPEN.end(), cmp);//对OPEN表的节点按照估价函数的值进行从大到小排序,每次取估价函数值最小的节点即表中的最后一个节点
    }
    cout << "Failed." << endl;          //未找到Sg=N,失败
    FreeCLOSED(CLOSED);                 //释放CLOSED表
    return;
}

void A_algorithm::PrintPath(Node* head)
{
    if (head == NULL)
        return;
    else
    {
        PrintPath(head->parent);
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if (head->Node[i][j] == 0)
                    cout << "  ";
                else
                    cout << head->Node[i][j] << " ";
            }
            cout << endl;
        }
        cout << endl;
    }
}

void A_algorithm::FreeCLOSED(Node* CLOSED)
{
    Node* current;
    while (CLOSED != NULL)
    {
        current = CLOSED->next;
        free(CLOSED);
        CLOSED = current;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值