一、实验内容
编写九宫重排问题的启发式搜索(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;
}
}