启发式算法A实例——八数码游戏

        令评价函数f(n)=d(n)+w(n), 其中 d(n):节点n在搜索图中的节点深度,对g(n)的度量; w(n):代表启发式函数h(n), 其值是节点n与目标状态节点ng相比较的代价,错位的棋牌个数(不考虑空格); 实现算法A搜索初始状态到目标状态的解路径。

针对八数码游戏,采用任意一种编程语言实现算法A,本文选择的是相对较快的C++

#include<iostream>
#include<map>
#include<vector>
using namespace std;
map<char,int>open;
map<char,int> close;
map<char,int*>matrix;
char index='a';
int target[9]={1,2,3,8,-100,4,7,6,5};
int getw(int a[]){//得到w值 
	int w=0;
	for(int i=0;i<9;i++){
		if(a[i]!=target[i])
		w++;
	}
	return w;
}
void disp(int a[]){
	cout<<"//"<<endl;
	for(int i=0;i<9;i++){
		cout<<a[i]<<" ";
		if(i==2||i==5||i==8){
			cout<<endl;
		}
	}
	cout<<"//"<<endl;
}
bool check(int a[]){//检查矩阵和open表里面的矩阵的差异
	disp(a);	
	if(matrix.size()==0)
	{
		return true;
	 } 
		map<char,int*>::iterator p=matrix.begin();
		while(p!=matrix.end()){				
			for(int i=0;i<9;i++){
				if(a[i]!=p->second[i]){//有一个不同即可换下一个查看 
					break;
				}
				if(i==8){//完全重复 
					return false;
				}
			}
			p++;
		}
	return true;//没有重复 
}
void getChild(int a[],char ch){
	close[ch]=open[ch];
	open.erase(ch);
	disp(a);
	int x=0,temp=0;
	for(int i=0;i<9;i++){
		if(a[i]==0)
		x=i;
	}
	vector<int> di;//1,2,3,4 上右下左 
	if(x>2){
		di.push_back(1);
	}
	if(x<6){
		di.push_back(3);
	} 
	if(x%3!=0){
		di.push_back(4);
	}
	if(x!=2&&x!=5&&x!=8){
		di.push_back(2);
	}
	while(di.size()>0){
		int *mt=new int[9];
		for(int i=0;i<9;i++){
			mt[i]=a[i];
		}
		switch(di.back()){
			case 1:
				{
					//cout<<"上移"<<endl;
					mt[x]=mt[x-3];
					mt[x-3]=0;
					di.pop_back();
					break;
				}
			case 2:
				{
				///	cout<<"右移"<<endl;
					mt[x]=mt[x+1];
					mt[x+1]=0;
					di.pop_back();
					break;
				}
			case 3:
				{
				//	cout<<"下移"<<endl;
		 			mt[x]=mt[x+3];
					mt[x+3]=0;
					di.pop_back();
					break;
				}
			case 4:
				{
				//	cout<<"左移"<<endl;
		 			mt[x]=mt[x-1];
		 			mt[x-1]=0;
		 			di.pop_back();
		 			break;
				}
			default:;
			
		}
		cout<<"移动之后的矩阵为"<<endl;
		disp(mt);
		 if(check(mt)==true){
		 	char myIndex=index++;
		 	temp=getw(mt);
		 	cout<<"标记为:"<<myIndex<<temp<<endl;
		 	open[myIndex]=temp;
		 	matrix[myIndex]=mt;		 	
		 }else{
		 	cout<<"上面的重复了"<<endl;
		 	delete mt;
		 }
			
	}
}
char sortOpen(){//整理open表
	map<char,int>::iterator p=open.begin();
	char a;
	int b=100;
	while(p!=open.end()){
		if(p->second<b){
			b=p->second;
			a=p->first;
		}
		p++;
	}
	cout<<"最小的条目为:"<<a<<b<<endl;
	if(b==1){
		cout<<"target found"<<endl;
		return a-32;
	}
	return a;
} 
int main(){
	int s[9]={1,0,3,7,2,4,6,8,5};
//	cout<<"初始矩阵s装入matrix表"<<endl;
	matrix['s']=s;
	open['s']=getw(s);
	getChild(s,'s');
	while(1){
		char a=sortOpen();
		if(a>'A'&&a<'Z'){
			cout<<"done"<<endl;
			break;
		}else{
			getChild(matrix[a],a);
		}
	}
	matrix.erase('s');
	map<char,int*>::iterator p=matrix.begin();
	cout<<"总共有"<<matrix.size()<<"个条目"<<endl;
	while(p!=matrix.end()){
		cout<<"空间清理"<<p->first<<"完毕"<<endl;
		delete p->second;
		p++;		
	}		
} 

想要仔细看代码的各个函数输入输出的,处理过程的,运行一下下面的代码

#include<iostream>
#include<map>
#include<vector>
using namespace std;
map<char,int>open;
map<char,int> close;
map<char,int*>matrix;
char index='a';
int target[9]={1,2,3,8,-100,4,7,6,5};

int getw(int a[]){
	//cout<<"对于检查函数"<<endl;
	int w=0;
	for(int i=0;i<9;i++){
		if(a[i]!=target[i])
		w++;
	}
	cout<<"w值为:"<<w<<endl;
	return w;
}
void disp(int a[]){
	cout<<"//"<<endl;
	for(int i=0;i<9;i++){
		cout<<a[i]<<" ";
		if(i==2||i==5||i==8){
			cout<<endl;
		}
	}
	cout<<"//"<<endl;
}

bool check(int a[]){//检查矩阵和open表里面的矩阵的差异
	cout<<"检查矩阵:"<<endl;
	disp(a);
	cout<<"和open表里面的矩阵的差异"<<endl;	
	if(matrix.size()==0)
	{
		cout<<"表为空"<<endl;
		return true;
	 } 
		map<char,int*>::iterator p=matrix.begin();
	//	disp(p->second);
		while(p!=matrix.end()){				
			for(int i=0;i<9;i++){
				if(a[i]!=p->second[i]){
					break;
				}
				if(i==8){
					return false;
				}
			}
			p++;
		}
		cout<<"全部不同"<<endl;
	return true;
}
void getChild(int a[],char ch){
	cout<<"============对下列矩阵进行扩展:==============="<<endl;
	cout<<"将open表中的对应条目"<<ch<<open[ch]<<"装进close表"<<endl;
	close[ch]=open[ch];
	cout<<"同时删除open表中对应条目,初始大小:"<<open.size()<<endl;
	open.erase(ch);
	cout<<"之后大小:"<<open.size()<<endl;
	disp(a);
	int x=0,temp=0;
	for(int i=0;i<9;i++){
		if(a[i]==0)
		x=i;
	}
//	cout<<"0的坐标为("<<x<<")"<<endl;
	vector<int> di;//1,2,3,4 上右下左 
	if(x>2){
		di.push_back(1);
	}
	if(x<6){
		di.push_back(3);
	} 
	if(x%3!=0){
		di.push_back(4);
	}
	if(x!=2&&x!=5&&x!=8){
		di.push_back(2);
	}
	while(di.size()>0){
		int *mt=new int[9];
		for(int i=0;i<9;i++){
			mt[i]=a[i];
		}
		switch(di.back()){
			case 1:
				{
					cout<<"上移"<<endl;
					mt[x]=mt[x-3];
					mt[x-3]=0;
					di.pop_back();
					break;
				}
			case 2:
				{
					cout<<"右移"<<endl;
					mt[x]=mt[x+1];
					mt[x+1]=0;
					di.pop_back();
					break;
				}
			case 3:
				{
					cout<<"下移"<<endl;
		 			mt[x]=mt[x+3];
					mt[x+3]=0;
					di.pop_back();
					break;
				}
			case 4:
				{
					cout<<"左移"<<endl;
		 			mt[x]=mt[x-1];
		 			mt[x-1]=0;
		 			di.pop_back();
		 			break;
				}
			default:;
			
		}
		cout<<"之后的矩阵为"<<endl;
		disp(mt);
		 if(check(mt)==true){
		 	char myIndex=index++;
		 	temp=getw(mt);
		 	cout<<"标记为:"<<myIndex<<temp<<endl;
		 	cout<<"装入open表和ma表"<<endl; 
		 	open[myIndex]=temp;
		 	matrix[myIndex]=mt;		 	
		 }else{
		 	cout<<"上面的重复了,不装入"<<endl;
		 	delete mt;
		 }
			
	}
// cout<<"此时二者的长度为:"<<open.size()<<":"<<matrix.size()<<endl;
}
char sortOpen(){
	cout<<"整理open表"<<endl;
	map<char,int>::iterator p=open.begin();
	char a;
	int b=100;
	while(p!=open.end()){
		if(p->second<b){
			b=p->second;
			a=p->first;
		}
		p++;
	}
	cout<<"最小的条目为:"<<a<<b<<endl;
	if(b==1){
		cout<<"target found"<<endl;
		return a-32;
	}
	return a;
} 
int main(){
	int s[9]={1,0,3,7,2,4,6,8,5};
	cout<<"初始矩阵s装入matrix表"<<endl;
	matrix['s']=s;
	open['s']=getw(s);
	getChild(s,'s');
	while(1){
		char a=sortOpen();
		if(a>'A'&&a<'Z'){
			cout<<"done"<<endl;
			break;
		}else{
			getChild(matrix[a],a);
		}
	}
	matrix.erase('s');
	map<char,int*>::iterator p=matrix.begin();
	cout<<"总共有"<<matrix.size()<<"个条目"<<endl;
	while(p!=matrix.end()){
		cout<<"空间清理"<<p->first<<"完毕"<<endl;
		delete p->second;
		p++;		
	}		
} 

        我的经验是不要使用二维数组来装图的信息,因为二维数组和map合不来。就比如说上面的代码用到一种数据类型:map<char,int *>,这样可以很好地使用map来装每个拓展出来的图,如果使用二维数组,改为:map<char,int**>,是报错的,或者用:map<char,int(*)[3]>倒也不报错,但是没有办法和int **类型或者int [][3]相互赋值,总之二维数组会带来一大堆麻烦,一维数组才是光明正道。

        另外就是储存每个拓展出来的子图的时候,我们储存的都是他的地址,所以产生每个字图之前都需要使用new来建立他自己的空间,然后赋初始值,最后再delete清理。切记不要使用初始矩阵图来进行变换。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值