(完整版)启发式搜索算法
人工智能基础实验报告
实验名称:八数码问题
姓名:张俊
学号:2220092333
指导老师:邓安生
启发式搜索算法
1. 实验内容:
使用启发式搜索算法求解8数码问题。
⑴ 编制程序实现求解8数码问题A *算法,采用估价函数
()()()()
w n f n d n p n ??=+???, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数;()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。
⑵ 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是()p n 的上界的()h n 的定义,并测试使用该估价函数是否使算法失去可采纳性。
2. 实验目的
熟练掌握启发式搜索A *算法及其可采纳性。
3. 实验原理
八数码问题是在3行和3列构成的九宫棋盘上放置数码为1到8的8个棋盘,剩下一个空格的移动来不断改变棋盘的布局,求解这类问题的方法是:给定初始布局(即初始状态)和目标布局(即目标状态),定义操作算子的直观方法是为每个棋牌制定一套可能的走步》上,下,左,右四种移动,再根据所定义的启发式搜索函数在搜索过程中选择最合适的操作算子,得到最优的路径。
4.源代码
#include
#include
#include
#include
#include
#include
#include //以上为C++源文件
using namespace std;
static int space=0;
int target[9];
class EightNum//定义一个EightNum 类
{
public:
int num[9];
int f;//初始状态与目标状态相比,棋子错放个数
int deap;//深度
int evalfun;//状态的估价值
EightNum *parent;
//以下为类内成员函数的声明
EightNum(int nnum[9]);
int get_evalfun();
int get_deapfun();
void eval_func(int id);
int Canspread(int n);
void Spreadchild(int n);
void getnum(int num1[9]);
void setnum(int num1[9]);
void show(void);
int operator ==(EightNum& NewEightN);
int operator ==(int num2[9]);
int Shownum();
};
//-----------------------以下为EightNum类成员函数定义-----------------// class Stack
{
private:
EightNum * eightnum;
public:
Stack * next;
EightNum * Minf();
EightNum * Belong(EightNum * suc);
void Putinto(EightNum * suc);
};
EightNum::EightNum(int nnum[9]){//此函数功能为:初始化num[];for(int i=0;i<9;i++)
num[i]=nnum[i];
f=0;
deap=0;
parent=NULL;
}
int EightNum::get_evalfun(){
return evalfun;
}
int EightNum::get_deapfun(){
return deap;
}
void EightNum::eval_func(int id){//此函数为估价函数
int i,qifa;
qifa=0;
switch(id){
case 1:{
for(i=0;i<9;i++){
if(num[i]!=target[i])
qifa++;
}
break;
}
case 2:{
int j, h1,h2;
for(i=0;i<9;i++){
for(j=0;j<9;j++){
if(num[j]==i)h1=j;
if(target[j]==i)h2=j;
}
qifa+=(int)(fabs((double)(h1/3 - h2/3)) + fabs((double)(h1%3 - h2%3)));
}
break;
}
case 3:{
int j, h1,h2;
for(i=0;i<9;i++){
for(j=0;j<9;j++){
if(num[j]==i)h1=j;
if(target[j]==i)h2=j;
}
qifa+=(int)(fabs((double)(h1/3 - h2/3)) + fabs((double)(h1%3 - h2%3)));
}
qifa=3*qifa;
break;
}
default :break;
}
f=qifa;
if(this->parent==NULL) deap=0;
else deap=this->parent->deap+1;
evalfun=deap+f;
}
int EightNum::Canspread(int n)
{//判断空格"0"可否移动
int i,flag = 0;
for(i = 0;i < 9;i++)
if(this->num[i] == 0)break;
switch(n)
{
case 1:
if(i/3 != 0)flag = 1;break;
case 2:
if(i/3 != 2)flag = 1;break;
case 3:
if(i%3 != 0)flag = 1;break;
case 4:
if(i%3 != 2)flag = 1;break;
default:break;
}
return flag ;
}
void EightNum::Spreadchild(int n)
{//扩展child节点的子节点
int i,loc,qifa;
for(i = 0;i < 9;i++)
this->num[i] = this->parent->num[i];
for(i = 0;i < 9;i++)
if(this->num[i] == 0)break;
if(n==0)
loc = i%3+(i/3 - 1)*3;
else if(n==1)
loc = i%3+(i/3 + 1)*3;
else if(n==2)
loc = i%3-1+(i/3)*3;
else
loc = i%3+1+(i/3)*3;
qifa = this->num[loc];
this->num[i] = qifa;
this->num[loc] = 0;
}
void EightNum::getnum(int num1[9]){ for(int i=0;i<9;i++)
num1[i]=num[i];
}
void EightNum::setnum(int num1[9]){ for(int i=0;i<9;i++)
num[i]=num1[i];
}
void EightNum::show(){//输出函数
for(int i=0;i<9;i++){
cout<if((i+1)%3==0)
cout<<"\n";
}
cout<<"--------------------";
}
int EightNum::Shownum()
{
if(this == NULL)return 0;
else
{
int n = this->parent->Shownum();
this->show();
cout<return n+1;
}
}
int EightNum::operator ==(EightNum& NewEightN){
int compere=1;
for(int i=0;i<9;i++)
if(num[i]!=NewEightN.num[i]){
compere=0;
break;
}
if(compere==0) return 0;
else return 1;
}
//-----------------------以下为分函数的定义---------------------//
//判断是否有解的函数
int solve(int num[9],int target[9]){
int i,j;
int num_con=0,tar_con=0;
for(i=0;i<9;i++)
for(j=0;j
if(num[j]num_con++;
if(target[j]tar_con++;
}
num_con=num_con%2;
tar_con=tar_con%2;
if((num_con==0 && tar_con==0)||(num_con==1 && tar_con==1))
return 1;
else
return 0;
}
EightNum * Stack::Minf()
{
Stack * qifa =this->next;
Stack * min = this->next;
Stack * minp = this;
EightNum * minx;
while(qifa->next != NULL)
{
if((qifa->next->eightnum->get_evalfun()) < (min->eightnum->get_evalfun()))
{
min = qifa->next;
minp = qifa;
}
qifa = qifa->next;
}
minx = min->eightnum;
qifa = minp->next;
minp->next = minp->next->next;
free(qifa);
return minx;
}
//判断节点是否属于OPEN表或CLOSED表
EightNum * Stack::Belong(EightNum * suc)
{
Stack * qifa = this-> next ;
if(qifa == NULL)return NULL;
while(qifa != NULL)
{
if(suc==qifa->eightnum)return qifa ->eightnum;
qifa = qifa->next;
}
return NULL;
}
//把节点存入OPEN 或CLOSED 表中
void Stack::Putinto(EightNum * suc)
{
Stack * qifa;
qifa =(Stack *) malloc(sizeof(Stack));
qifa->eightnum = suc;
qifa->next = this->next;
this->next = qifa;
}
int BelongProgram(EightNum * suc ,Stack *Open ,Stack *Closed ,EightNum goal,int m )
{
EightNum * qifa = NULL;
int flag = 0;
if((Open->Belong(suc) != NULL) || (Closed->Belong(suc) != NULL))
{
if(Open->Belong(suc) != NULL) qifa = Open->Belong(suc);
else qifa = Closed->Belong(suc);
flag=1;
}
else
{
Open->Putinto(suc);
suc->eval_func(m);
}
return flag;
}
//扩展后继节点总函数
void Spread(EightNum * suc, Stack * Open, Stack * Closed, EightNum goal,int m)
{
int i;
EightNum * child;
for(i = 0; i < 4; i++)
{
if(suc->Canspread(i+1))
{
space++;
child = (EightNum *) malloc(sizeof(EightNum));
child->parent = suc;
child->Spreadchild(i);
child->eval_func(m);
if(BelongProgram(child, Open, Closed, goal,m)) //判断子节点是否属于OPEN或CLOSED表
free(child);
}
}
}
//执行函数
EightNum * Process(EightNum * org, EightNum goal, Stack * Open, Stack * Closed,int m)
{
while(1)
{
if(Open->next == NULL)return NULL;
EightNum * minf =Open->Minf();
Closed->Putinto(minf);
if((*minf)==goal)return minf;
Spread(minf, Open, Closed, goal,m);
}
}
//------------------------A*算法搜索函数----------------------//
void A(int id,EightNum start,EightNum Target)
{
EightNum * result;
space=0;
float time;
Stack *Open = (Stack *) malloc(sizeof(Stack));
Open->next = NULL;
Stack *Closed = (Stack *) malloc(sizeof(Stack));
Closed->next = NULL;
clock_t startt,finisht;
startt=clock();//开始时间
start.eval_func(id);
Open->Putinto(&start);
result = Process(&start, Target, Open, Closed,id); //进行剩余的操作
cout<<"\n搜索过程:\n"<Shownum()<finisht=clock();
time=(float)(finisht-startt);
cout<cout<