令评价函数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清理。切记不要使用初始矩阵图来进行变换。