A*算法求解15数码问题

一、问题描述

15数码问题同八数码问题,是人工智能中一个很典型的智力问题。15数码问题是在4×4方格盘上,放有15个数码,剩下一个位置为空(方便起见,用0表示空),每一空格其上下左右的数码可移至空格。本问题给定初始位置和目标位置,要求通过一系列的数码移动,将初始状态转化为目标状态。

状态转换的规则:空格四周的数移向空格,我们可以看作是空格移动,它最多可以有4个方向的移动,即上、下、左、右。问题的求解方法,就是从给定的初始状态出发,不断地将空格上下左右的数码移至空格,将一个状态转化成其它状态,直到产生目标状态。

本报告利用A*算法,给出了15数码问题的C++算法实现。

二、A*算法

2.1算法简介

A*(A-Star)算法是求解最短路最有效的直接搜索方法,也是许多其他问题的常用启发式算法。

其基本思想是:定义一个评价函数f,对当前的搜索状态进行评估,找出一个最有希望的结点来扩展。评价函数形式为:f(n)=g(n)+h(n)。其中f(n)是从初始状态经由状态n到目标状态的代价估计,g(n) 是在状态空间中从初始状态到状态n的实际代价,h(n) 是从状态n到目标状态的最佳路径的估计代价。

A*算法要求启发函数中的h(n)是处在h*(n)的下届范围,即满足h(n)<=h*(n).

2.2评价函数设置

本报告取f(n)=g(n)+h(n)=d(n)+P(n)。其中,d(n)为当前结点的深度,P(n)为当前状态下各将牌到目标位置的距离之和。距离的定义为:“某将牌行下标与目标位置行下标之差的绝对值 + 列下标与目标位置列下标之差的绝对值”。距离越小,该节点的效果越好。某个状态所有将牌到目标位置的距离之和用“h值”表示。

三、算法设计

本课程使用产生式系统的结构。

3.1综合数据库

主要包括:目标状态、初始状态、当前状态、状态所属表、当前状态的评价函数值、当前状态的移动方向。

3.2规则库

主要包括:向左移动、向上移动、向右移动、向下移动。

3.3控制系统

算法的功能:产生15数码问题的解(由初始状态到达目标状态的过程) 

输入:初始状态,目标状态 

输出:从初始状态到目标状态的一系列过程 

算法描述: 

Begin: 
读入初始状态和目标状态,并计算初始状态评价函数值f; 
初始化两个open表和closed表,将初始状态放入open表中
If(open表为空)
    查找失败;
End if
else  
①	在open表中找到评价值最小的节点,作为当前结点,并放入closed表中; 
②	判断当前结点状态和目标状态是否一致,若一致,跳出循环;否则跳转到③; 
③	对当前结点,分别按照上、下、左、右方向移动空格位置来扩展新的状态结点,并计算新扩展结点的评价值f并记录其父节点; 
④	对于新扩展的状态结点,进行如下操作:
A.新节点既不在open表中,也不在closed表中,则ADD (mj, OPEN);
B.新节点在open表中,则IF f(n-mk) < f(mk)  
THEN f(mk):=f(n-mk), 
C.新节点在closed表中,则IF f(n-ml) < f(ml)  
THEN f(ml):=f(n-ml),     
⑤	把当前结点从open表中移除; 
End if
End

四、实现

VS2012

4.1 S类(表示状态)

#include "stdafx.h"
#include "S.h"
#include <math.h>

S::S(void)
{
	int G0[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};
	memcpy(G,G0,sizeof(int)*4*4);
	state=0;
}
void S::setS0(int d0,int f0){
	d=d0;
	f=f0;
}
void S::setS(int s0[4][4]){
	memcpy(s,s0,sizeof(int)*4*4);
//	setH();
}
void S::setState(int state0){
	state=state0;
}
void S::setH(){
	h=0;
	int p=0;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			for(int m=0;m<4;m++){
				for(int k=0;k<4;k++){
					if(s[i][j]==G[m][k]&&s[i][j]!=0){
						p=abs(i-m)+abs(j-k);
					}
				}
			}
			h=h+p;
			p=0;
		}
	}
	setD();
}
int S::getH(){
	return h;
}
void S::setD(){
	d=d+1;
	setF();
}
int S::getD(){
	return d;
}
void S::setF(){
	f=getD()+getH();
}
int S::getF(){
	return f;
}

bool S::compare(int temps[4][4]){
	int temp[4][4];
	memcpy(temp,temps,sizeof(int)*4*4);
	int sum=0;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			if(s[i][j]==temps[i][j]){
				sum=sum+1;
			}
		}
	}
	if(sum==16){
		return 1;//1是目标
	}
	else
		return 0;
}

void S::show(){
//	int h=getH();
//	int result=compare(G);
//	cout<<h<<endl<<result<<endl;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			if(j!=3){
				if(s[i][j]<10){
					cout<<s[i][j]<<"  ";
				}
				else
					cout<<s[i][j]<<" ";
			}
			else
				cout<<s[i][j]<<endl;
		}
	}
	cout<<"D值为:"<<d<<"    ";
	cout<<"H值为:"<<h<<"    ";
	cout<<"F值为:"<<f<<endl;
	cout<<endl;
}

void S::error(){
	cout<<endl<<"查找失败!"<<endl;
}

void S::success(int i){
	cout<<endl<<"使用"<<i<<"步,找到目标!"<<endl<<endl;
}

bool S::Up(){
	int i=0,j=0;
	int temp;
	if(Direct!=1){//上一步不是向下移
		Direct=0;//这步是向上移
		for(i=0;i<4;i++){
			for(j=0;j<4;j++){
				if(s[i][j]==0&&i-1>=0){
					temp=s[i][j];
					s[i][j]=s[i-1][j];
					s[i-1][j]=temp;
					setH();
					return 1;
					break;
				}
			}
		}
	}
	setH();
	return 0;
}
bool S::Down(){
	int i=0,j=0;
	int temp;
	if(Direct!=0){//上一步不是向上移
		Direct=1;//这步是向下移
		for(i=0;i<4;i++){
			for(j=0;j<4;j++){
				if(s[i][j]==0&&i+1<4){
					temp=s[i][j];
					s[i][j]=s[i+1][j];
					s[i+1][j]=temp;
					setH();
					return 1;
					break;
				}
			}
		}
	}
	setH();
	return 0;

}
bool S::Left(){
	int i=0,j=0;
	int temp;
	if(Direct!=3){//上一步不是向右移
		Direct=2;//这步是向左移
		for(i=0;i<4;i++){
			for(j=0;j<4;j++){
				if(s[i][j]==0&&j-1>=0){
					temp=s[i][j];
					s[i][j]=s[i][j-1];
					s[i][j-1]=temp;
					setH();
					return 1;
					break;
				}
			}
		}
	}
	setH();
	return 0;

}
bool S::Right(){
	int i=0,j=0;
	int temp;
	if(Direct!=2){//上一步不是向左移
		Direct=3;//这步是向右移
		for(i=0;i<4;i++){
			for(j=0;j<4;j++){
				if(s[i][j]==0&&j+1>0){
					temp=s[i][j];
					s[i][j]=s[i][j+1];
					s[i][j+1]=temp;
					setH();
					return 1;
					break;
				}
			}
		}
	}
	setH();
	return 0;

}

4.2 AStar类(算法描述)

#include "stdafx.h"
#include "AStar.h"
#include <algorithm>    // std::sort
using namespace std;


AStar::AStar(void)
{
	
	int G0[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};
	memcpy(G,G0,sizeof(int)*4*4);
	int ss0[4][4]={{5,1,2,4},{9,6,3,8},{13,15,10,11},{14,0,7,12}};
	//int ss0[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,0,14,15}};
	
	s0.setS0(-1,0);
	s0.setS(ss0);
	s0.setH();
	open.push_back(s0);//①初始状态放入OPEN表中
	s0.setState(1);//②改变s0的状态值,1为在OPEN表中
	step=-1;
}

/*
void AStar::show(){
	int h=open[0].getH();
	int result=open[0].compare(G);
	cout<<h<<endl<<result<<endl;
	
	switch (index0)
	{
	case 0:{
		cout<<"查找失败"<<endl;
		   }
	case 1:
		cout<<"OPEN表不为空"<<endl;
	default:
		break;
	}
	
}*/
void AStar::AA(){
	step++;
	if(open.size()!=0){
		BestS=open[0];
		BestS.show();
		closed.push_back(open[0]);//OPEN表第一个状态放入CLOSED表中
		open.erase(open.begin());//将OPEN表第一个状态删除

		if(BestS.compare(G)==1){
			BestS.success(step);
		}
		else{
			genChild();
			AA();
		}
	}
	else
		BestS.error();
	
}
void AStar::genChild(){
	U=BestS;
	D=BestS;
	L=BestS;
	R=BestS;
		if(L.Left()==1){
		L.setState(1);
		if(ifInOpen(L)!=1&&ifInClosed(L)!=1){
			open.push_back(L);
		}	
	//	L.show();
	}
	if(U.Up()==1){
		U.setState(1);
		if(ifInOpen(U)!=1&&ifInClosed(U)!=1){
			open.push_back(U);
		}	
		//	U.show();
	}
	if(R.Right()==1){
		R.setState(1);
		if(ifInOpen(R)!=1&&ifInClosed(R)!=1){
			open.push_back(R);
		}	
	//	R.show();
	}
	if(D.Down()==1){
		D.setState(1);
		if(ifInOpen(D)!=1&&ifInClosed(D)!=1){
			open.push_back(D);
		}	
	//	D.show();
	}


	reverse(open.begin(), open.end());
	sortOpen();
}

void AStar::sortOpen(){
    S min;
	vector<S> newOpen;
	sort(open.begin(),open.end(),compare);//降序排列
	/*
	vector<S>::iterator it;
	while(open.size()!=0){
		min=open[0];
		for(it=open.begin();it!=open.end();it++){
			if(it[0].getF()<min.getF()){
				min=it[0];
			}
		}
	}*/
}
bool AStar::compare(S pfirst,S psecond) //如果该vector存入的是对象的话该函数参数须是
{                                                    // 对象的引用,而不该是指针
	return pfirst.getF() < psecond.getF();
}
bool AStar::ifInOpen(S temp){
	int i=0;
	vector<S>::iterator it;
	for(it=open.begin();it!=open.end();it++){
		if(temp.compare(it[0].s)&&temp.getF()<it[0].getF()){
			open.erase(open.begin()+i);
			open.push_back(temp);
			return 1;
		}
		i++;
	}
	return 0;
}

bool AStar::ifInClosed(S temp){
	int i=0;
	vector<S>::iterator it;
	for(it=closed.begin();it!=closed.end();it++){
		if(temp.compare(it[0].s)&&temp.getF()<it[0].getF()){
			closed.erase(closed.begin()+i);
			open.push_back(temp);
			return 1;
		}
		i++;
	}
	return 0;
}

4.3主函数

// AI.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include "AStar.h"
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	//int s0[4][4]={{5,1,2,4},{9,6,3,8},{13,15,10,11},{14,0,7,12}};
	/*int s0[]={5,1,2,4,9,6,3,8,13,15,10,11,14,0,7,12};
	int g[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
	vector<int> s(s0,s0+16);
	vector<int> G(g,g+16);*/
	AStar test;
	test.AA();
	system("pause");
	return 0;
}



五、运行结果


初始矩阵:

5

1

2

4

9

6

3

8

13

15 

10 

11 

14 

0

7

12

 

目标矩阵:

1

2

3

4

5

6

7

8

9

10 

11 

12 

13 

14

15

0


 

  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值