用A算法实现的八数码问题C++源码
八数码C语言A算法详细代码
#include<iostream>#include<time.h>#include<windows.h>#include<vector>#include<cmath>using namespace std;struct node{int a[3][3]; //存放矩阵int father; //父节点的位置int gone; //是否遍历过,1为是,0为否int fn; //评价函数的值int x,y; //空格的坐标int deep; //节点深度};vector<node> store; //存放路径节点int mx[4]={-1,0,1,0};int my[4]={0,-1,0,1}; //上下左右移动数组int top; //当前节点在store中的位置bool check(int num) //判断store[num]节点与目标节点是否相同,目标节点储存在store[0]中{for(int i=0;i<3;i++){for(int j=0;j<3;j++){if(store[num].a[i][j]!=store[0].a[i][j])return false;}}return true;}bool search(int num) //判断store[num]节点是否已经扩展过 ,没有扩展返回true{int pre=store[num].father; //pre指向store[num]的父节点位置bool test=true;while(!pre){ //循环直到pre为0,既初始节点for(int i=0;i<3;i++){for (int j=0;j<3;j++){if(store[pre].a[i][j]!=store[num].a[i][j]){test=false;break;}}if(test==false) break;}if(test==true) return false;pre=store[pre].father; //pre继续指向store[pre]父节点位置}return true;}void print(int num) //打印路径,store[num]为目标节点{vector<int> temp; //存放路径int pre=store[num].father;temp.push_back(num);while(pre!=0){ //从目标节点回溯到初始节点temp.push_back(pre);pre=store[pre].father;}cout<<endl;cout<<"*********数码移动步骤*********"<<endl;int mm=1; //步数for(int m=temp.size()-1;m>=0;m--){cout<<"---第"<<mm<<"步---:"<<endl;for(int i=0;i<3;i++){for(int j=0;j<3;j++){cout<<store[temp[m]].a[i][j]<<" ";}cout<<endl;}mm++;cout<<endl;}cout<<"所需步数为: "<<store[num].deep<<endl;return;}int get_fn(int num) //返回store[num]的评价函数值{int fn_temp=0; //评价函数值bool test=true;for(int i=0;i<3;i++){ //当找到一个值后,计算这个值位置与目标位置的距离差,test置为false后继续寻找下一个值for(int j=0;j<3;j++){test=true;for(int k=0;k<3;k++){for(int l=0;l<3;l++){if((store[num].x!=i||store[num].y!=j)&&store[num].a[i][j]==store[0].a[k][l]){ //寻值时排除空格位fn_temp=fn_temp+abs(i-k)+abs(j-l);test=false;}if(test==false) break;}if(test==false) break;}}}fn_temp=fn_temp+store[num].deep; //加上节点深度return fn_temp;}void kongxy(int num) //获得空格坐标{for(int i=0;i<3;i++){for(int j=0;j<3;j++){if(store[num].a[i][j]==0){store[num].x=i;store[num].y=j;}}}return;}int main(){cout<<"-----------A*算法解决8数码问题------------"<<endl;while(true){store.clear(); //清空storevector<int> open; //建立open表int i,j,m,n,f;int min; //store[min]储存fn值最小的节点int temp;bool test;top=1; //当前节点在store的位置,初始节点在store[1]int target[9];int begin[9]; //储存初始状态和目标状态,用于判断奇偶int t1=0,t2=0; //初始状态和目标状态的奇偶序数node node_temp;store.push_back(node_temp);store.push_back(node_temp); //用于创建store[0]和store[1],以便下面使用cout<<"请输入初始数码棋盘状态,0代表空格:"<<endl; //输入初始状态,储存在store[1]中test=false;while(test==false){f=0;for(i=0;i<3;i++){for(j=0;j<3;j++){cin>>temp;store[1].a[i][j]=temp;begin[f++]=temp;}}test=true;for(i=0;i<8;i++){ //检查是否有重复输入,若有则重新输入for(j=i+1;j<9;j++){if(begin[i]==begin[j]){test=false;break;}}if(test==false) break;}if(test==false) cout<<"输入重复,请重新输入:"<<endl;}kongxy(1); //找出空格的坐标cout<<"请输入目标数码棋盘状态,0代表空格: "<<endl; //输入目标状态,储存在store[0]中test=false;while(test==false){f=0;for(i=0;i<3;i++){for(j=0;j<3;j++){cin>>temp;store[0].a[i][j]=temp;target[f++]=temp;}}test=true;for(i=0;i<8;i++){ //检查是否有重复输入,若有则重新输入for(j=i+1;j<9;j++){if(target[i]==target[j]){test=false;break;}}if(test==false) break;}if(test==false){cout<<"输入重复,请重新输入:"<<endl;continue; //若重复,重新输入}for(i=0;i<9;i++){ //检查目标状态与初始状态是否匹配test=false;for(j=0;j<9;j++){if(begin[i]==target[j]){test=true;break;}}if(test==false) break;}if(test==false) cout<<"输入与初始状态不匹配,请重新输入:"<<endl;}for(i=1;i<9;i++){ //判断奇偶序数是否相同,若不相同则无法找到路径for(j=1;i-j>=0;j++){if(begin[i]>begin[i-j]){if(begin[i-j]!=0) t1++;}}}for(i=1;i<9;i++){for(j=1;i-j>=0;j++){if(target[i]>target[i-j]){if(target[i-j]!=0) t2++;}}}if(!(t1%2==t2%2)){cout<<"无法找到路径."<<endl;cout<<endl;//system("pause");//return 0;continue;}LARGE_INTEGER Freg;LARGE_INTEGER Count1,Count2;QueryPerformanceFrequency(&Freg);QueryPerformanceCounter(&Count1);//获取时间Count1double d;store[1].father=0; //初始化参数store[1].gone=0;store[1].deep=0; //初始节点的父节点为0store[1].fn=get_fn(1);if(check(1)){ //判断初始状态与目标状态是否相同print(1);//system("pause");//return 0;cout<<endl;continue;}open.push_back(1); //把初始状态在store中的位置数压入open表中while(!open.empty()){ //当open表不为空时,开始寻找路径if(check(top)) break;min=top;int i_min=0;for(i=0;i<open.size();i++){ //遍历open表中元素,找出store中fn值最小的节点if(store[open[i]].fn<=store[min].fn&&store[open[i]].gone==0){min=open[i];i_min=i;}}store[min].gone=1;open.erase(open.begin()+i_min); //把最小节点标记遍历过,并从open表中删除m=store[min].x;n=store[min].y; //空格坐标for(f=0;f<4;f++){ //上下左右移动空格i=m+mx[f];j=n+my[f];if(i>=0&&i<=2&&j>=0&&j<=2){ //当变换后的空格坐标在矩阵中时,开始移动top++;store.push_back(store[min]); //把store[min]压入store中成为新增节点,位置为store[top]store[top].father=min; //新增节点的父节点为minstore[top].gone=0; //新增节点未被访问store[top].deep=store[min].deep+1; //新增节点的深度为父节点深度+1temp=store[top].a[m][n]; //交换空格与相邻数字store[top].a[m][n]=store[top].a[i][j];store[top].a[i][j]=temp;store[top].x=i; //移动后的空格坐标store[top].y=j;store[top].fn=get_fn(top); //移动后的fn值open.push_back(top); //把top压入open表中if(check(top)){ //检查是否到达目标print(top);//system("pause");//return 0;break;}if(search(top)==false){ //检查新增节点是否被访问过,若访问过,则删除此节点top--;store.pop_back();open.pop_back();}}}}QueryPerformanceCounter(&Count2);//获取时间Count2d=(double)(Count2.QuadPart-Count1.QuadPart)/(double)Freg.QuadPart*1000.0;//计算时间差,d的单位为ms.cout<<"算法时间为为"<<d<<" ms."<<endl;cout<<endl;}return 0;system("pause");}。
用A算法实现的八数码问题C++源码
用A算法实现的八数码问题C++源码用A*算法实现的八数码问题C++源码#include <iomanip>#include <stdlib.h>#include <iostream.h>#include <time.h>#include <stdio.h>#include <conio.h>//using namespace std;//定义默认目标状态static int target[9]={1,2,3,8,0,4,7,6,5};//八数码类class EightNum{private:int num[9];int diffnum;//与目标状态位置不同的数的个数. int deapth;//派生的深度.int evalfun;//状态的估价值public:EightNum *parent;//生成当前状态的父状态. EightNum *state_pre;//当前状态前生成状态. EightNum *state_next;//当前状态后生成状态.//成员函数声明EightNum(void);EightNum(int initnum[9]);int get_evalfun();void eval_func();void getnum(int num1[9]);void setnum(int num1[9]);void show(void);void show_spec(int i);int null_position(void);EightNum& operator =(EightNum& NewEightN);EightNum& operator =(int num2[9]);int operator ==(EightNum& NewEightN);int operator ==(int num2[9]);};//八数码类定义//八数码类成员函数定义EightNum::EightNum(void){//初始化数组num[]for(int i=0;i<9;i++)num[i]=i;}EightNum::EightNum(int initnum[9]){//用输入的数组初始化num[]for(int i=0;i<9;i++)num[i]=initnum[i];}int EightNum::get_evalfun(){//返回估价值return evalfun;}void EightNum::eval_func(){//估价函数int i,temp;temp=0;for(i=0;i<9;i++){if(num[i]!=target[i])temp++;}diffnum=temp;if(this->parent==NULL) deapth=0;else deapth=this->parent->deapth+1;evalfun=deapth+temp;}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<<num[i]<<" ";if((i+1)%3==0)cout<<"\n";}}void EightNum::show_spec(int i){//结果步骤输出函数cout<<num[i];cout<<"<--";}int EightNum::null_position(){//查找空格位置int i,j;for(i=0;i<9;i++){if(num[i]==0)j=i;}return j;}EightNum& EightNum::operator =(EightNum& NewEightN){//"="重载,针对八数码类的引用for(int i=0;i<9;i++)num[i]=NewEightN.num[i];diffnum=NewEightN.diffnum;deapth=NewEightN.deapth+1;evalfun=diffnum+deapth;return *this;}EightNum& EightNum::operator =(int num2[9]){//"="重载,用于数组赋值for(int i=0;i<9;i++)num[i]=num2[i];return *this;}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 EightNum::operator ==(int num2[9]){//"=="重载,用于数组的比较int compere=1;for(int i=0;i<9;i++)if(num[i]!=num2[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<i;j++){if(num[j]<num[i] && num[j]!=0)num_con++;if(target[j]<target[i] && target[j]!=0)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;elsereturn 0;}//空格移动函数int moveup(int num[9]){//空格上移for(int i=0;i<9;i++)if(num[i]==0) break;if(i<3) return 0;else {num[i]=num[i-3];num[i-3]=0;return 1;}}int movedown(int num[9]){//空格下移for(int i=0;i<9;i++)if(num[i]==0) break;if(i>5) return 0;else {num[i]=num[i+3];num[i+3]=0;return 1;}}int moveleft(int num[9]){//空格左移for(int i=0;i<9;i++)if(num[i]==0) break;if(i==0||i==3||i==6) return 0;else {num[i]=num[i-1];num[i-1]=0;return 1;}}int moveright(int num[9]){//空格右移for(int i=0;i<9;i++)if(num[i]==0) break;if(i==2||i==5||i==8) return 0;else {num[i]=num[i+1];num[i+1]=0;return 1;}}int exist(int num[9],EightNum *a){//判断是否重复搜索函数EightNum *t;for(t=a;t!=NULL;t=t->parent)if(*t==num) return 1;//调用"=="进行数组比较else return 0;}EightNum* find(EightNum *s){//寻找估价函数值最小的节点EightNum *m,*n;int min=s->get_evalfun();m=n=s;for(m=s;m!=NULL;m=m->state_next){if(min>m->get_evalfun()){n=m;min=m->get_evalfun();}return n;}}int main(void)//主函数{int i,j;int flag;int num[9];int error;do{//输入判断error=0;cout<<"请输入八数码问题的初始状态(用0代表空格,中间用空格隔开):"<<endl;for(i=0;i<9;i++){flag=0;cin>>num[i];for(j=0;j<i;j++)if(num[j]==num[i])flag=1;if(num[i]<0||num[i]>8||flag==1){error++;}}if(error!=0)cout<<"输入数据错误!请重新输入!"<<endl;}while(error!=0);cout<<"是否改变默认的目标状态?(y/n)";char input;cin>>input;int error1;if(input=='y'||input=='Y'){do{error1=0;cout<<"请输入新的目标状态(用0代表空格):"<<endl;for(i=0;i<9;i++){flag=0;cin>>target[i];for(j=0;j<i;j++)if(target[j]==target[i])flag=1;if(target[i]<0||target[i]>9||flag==1){error1++;}}if(error1!=0)cout<<"输入数据错误!请重新输入!"<<endl;}while(error1!=0);}//实例化初始状态和目标状态,并输出.EightNum start(num),T arget(target);start.parent=start.state_next=start.state_pre=NULL; start.eval_func();cout<<"初始状态为:"<<endl;start.show();cout<<"目标状态为:"<<endl;Target.show();//判断是否有解int m=solve(num,target);if(m==0){cout<<"此状态无解!"<<endl;return 0;}//进入A*算法搜索double time;clock_t startt,finisht;int ok=0;//结束标识位int space=0;//所耗费空间startt=clock();//开始时间EightNum *BestNode=&start,*Node=&start,*New8Num,*r; while(BestNode!=NULL&&ok!=1){BestNode=find(Node);if(*BestNode==Target){//调用"=="操作符ok=1;break;}r=BestNode->state_pre;//生成向上移的节点BestNode->getnum(num);if(moveup(num) && !exist(num,BestNode)){New8Num=new EightNum;New8Num->setnum(num);New8Num->parent=BestNode;New8Num->eval_func();New8Num->state_pre=r;if(r==NULL)Node=New8Num;elser->state_next=New8Num;r=New8Num;space++;}//生成向下移的节点BestNode->getnum(num);if(movedown(num) && !exist(num,BestNode)){ New8Num=new EightNum;New8Num->setnum(num);New8Num->parent=BestNode;New8Num->eval_func();New8Num->state_pre=r;if(r==NULL)Node=New8Num;elser->state_next=New8Num;r=New8Num;space++;}//生成向左移的节点BestNode->getnum(num);if(moveleft(num) && !exist(num,BestNode)){ New8Num=new EightNum;New8Num->setnum(num);New8Num->parent=BestNode;New8Num->eval_func();New8Num->state_pre=r;if(r==NULL)Node=New8Num;elser->state_next=New8Num;r=New8Num;space++;}//生成向右移的节点BestNode->getnum(num);if(moveright(num) && !exist(num,BestNode)){New8Num=new EightNum;New8Num->setnum(num);New8Num->parent=BestNode;New8Num->eval_func();New8Num->state_pre=r;if(r==NULL)Node=New8Num;elser->state_next=New8Num;r=New8Num;space++;}r->state_next=BestNode->state_next;if(BestNode->state_next!=NULL)BestNode->state_next->state_pre=r;BestNode->state_next=BestNode->state_pre=NULL; }finisht=clock();//输出搜索结果if(ok==1){time=(double)(finisht-startt)*1000/CLOCKS_PER_SEC; EightNum *p,*q=NULL;int step=0;for(p=BestNode->parent;p!=NULL;p->parent){if(step==0){i=8;p->show_spec(i);i=p->null_position();}else{p->show_spec(i);i=p->null_position();}if (step==8||step==18||step==28||step==38||step==48) cout<<"\n";step++;}cout<<"\nA*算法处理结果:所耗时间:";cout<<time;cout<<"ms, ";cout<<"所耗空间:";cout<<space;cout<<"块, ";cout<<"最短路径步数:";cout<<step;cout<<"步 !\n";}elsecout<<"\nA*算法无法找到最短路径!\n";}。
八数码问题C代码
*********************************************************************本函数是用A*算法来实现八数码的问题***算法的步骤如下:*1、初始化两个链表open和closed,将初始状态放入open表中*2、重复下列过程,直至找到目标结点为止,如果open表为空,那* 么查找失败;*3、从open表中拿出具有最小f值的结点(将这一结点称为BESTNODE),* 并放入closed表中;*4、如果BESTNODE为目标结点,成功求得解,退出循环;*5、如果BESTNODE不是目标结点,那么产生它的后继结点(此后继结* 点与其祖先的状态不同),后继结点组成一个链表;*6、对每个后继结点进行以下过程:*7、建立它到BESTNODE的parent指针;*8、如果此结点在open表中,首先将open表中的结点添加进BESTNODE* 的后继结点链中,然后计算两个结点的g值,如果此结点的g值小* 于open表中的结点时,open表中的结点改变parent指针,同时将* 此结点删除;*9、如果此结点在closed表中,首先将closed表中的结点添加进BESTNODE * 的后继结点中,然后计算两个结点的g值,如果此结点的g值小于* closed表中的结点时,closed表中的结点改变parent指针;将* closed表中的结点重新放入open表中,同时将此结点删除;*10、如果此结点既不在open表中也不再closed表中,那么添加此结点至* BESTNODE的后继结点链中。
***Author: 转载作者不详。
**2011.5.16**********************************************************************/#include "stdafx.h"#include <iostream>#include <cstdlib>#include <conio.h>#define size 3using namespace std;//定义二维数组来存储数据表示某一个特定状态typedef int status[size][size];struct SpringLink;//定义状态图中的结点数据结构typedef struct Node{status data;//结点所存储的状态Node *parent;//指向结点的父亲结点SpringLink *child;//指向结点的后继结点int fvalue;//结点的总的路径int gvalue;//结点的实际路径int hvalue;//结点的到达目标的苦难程度Node *next;//指向open或者closed表中的后一个结点}NNode , *PNode;//定义存储指向结点后继结点的指针的地址typedef struct SpringLink{Node *pointData;//指向结点的指针SpringLink *next;//指向兄第结点}SPLink , *PSPLink;//定义open表和close表PNode open;PNode closed;//开始状态与目标状态status startt = {2 , 8 , 3 , 1 , 6 , 4 , 7 , 0 , 5};status target = {1 , 2 , 3 , 8 , 0 , 4 , 7 , 6 , 5};//初始化一个空链表void initLink(PNode &Head){Head = (PNode)malloc(sizeof(NNode));Head->next = NULL;}//判断链表是否为空bool isEmpty(PNode Head){if(Head->next == NULL)return true;elsereturn false;}//从链表中拿出一个数据,通过FNode返回void popNode(PNode &Head , PNode &FNode){if(isEmpty(Head)){FNode = NULL;return;}FNode = Head->next;Head->next = Head->next->next;FNode->next = NULL;}//向结点的(最终)后继结点链表中添加新的子结点void addSpringNode(PNode &Head , PNode newData) {PSPLink newNode = (PSPLink)malloc(sizeof(SPLink)); newNode->pointData = newData;newNode->next = Head->child;Head->child = newNode;}//释放状态图中存放结点后继结点地址的空间//注意传入参数PSPLink引用类型void freeSpringLink(PSPLink &Head){PSPLink tmm;while(Head != NULL){tmm = Head;Head = Head->next;free(tmm);}}//释放open表与closed表中的资源void freeLink(PNode &Head){PNode tmn;tmn = Head;Head = Head->next;free(tmn);while(Head != NULL){//首先释放存放结点后继结点地址的空间freeSpringLink(Head->child);tmn = Head;Head = Head->next;free(tmn);}}//向普通链表中添加一个结点void addNode(PNode &Head , PNode &newNode) {newNode->next = Head->next;Head->next = newNode;}//向非递减排列的链表中添加一个结点void addAscNode(PNode &Head , PNode &newNode) {PNode P;PNode Q;P = Head->next;Q = Head;while(P != NULL && P->fvalue < newNode->fvalue) {Q = P;P = P->next;}//上面判断好位置之后,下面就是简单的插入了newNode->next = Q->next;Q->next = newNode;}//计算结点额h值,当前节点与目标节点数码错位个数int computeHValue(PNode theNode){int num = 0;for(int i = 0 ; i < 3 ; i++){for(int j = 0 ; j < 3 ; j++){if(theNode->data[i][j] != target[i][j])num++;}}return num;}//计算结点的f,g,h值void computeAllValue(PNode &theNode , PNode parentNode) {if(parentNode == NULL)theNode->gvalue = 0;elsetheNode->gvalue = parentNode->gvalue + 1;theNode->hvalue = computeHValue(theNode);theNode->fvalue = theNode->gvalue + theNode->hvalue;}//初始化函数,进行算法初始条件的设置void initial(){//初始化open以及closed表initLink(open);initLink(closed);//初始化起始结点,令初始结点的父节点为空结点PNode NULLNode = NULL;PNode Start = (PNode)malloc(sizeof(NNode));for(int i = 0 ; i < 3 ; i++){for(int j = 0 ; j < 3 ; j++){Start->data[i][j] = startt[i][j];}}Start->parent = NULL;Start->child = NULL;Start->next = NULL;computeAllValue(Start , NULLNode);//起始结点进入open表addAscNode(open , Start);}//将B节点的状态赋值给A结点void statusAEB(PNode &ANode , PNode BNode) {for(int i = 0 ; i < 3 ; i++){for(int j = 0 ; j < 3 ; j++){ANode->data[i][j] = BNode->data[i][j];}}}//两个结点是否有相同的状态bool hasSameStatus(PNode ANode , PNode BNode) {for(int i = 0 ; i < 3 ; i++){for(int j = 0 ; j < 3 ; j++){if(ANode->data[i][j] != BNode->data[i][j])return false;}}return true;}//结点与其祖先结点是否有相同的状态bool hasAnceSameStatus(PNode OrigiNode , PNode AnceNode) {while(AnceNode != NULL){if(hasSameStatus(OrigiNode , AnceNode))return true;AnceNode = AnceNode->parent;}return false;}//取得方格中空的格子的位置,通过row,col返回。
用VC++实现基于A_算法的八数码问题
4结论 本程序主要是用A*算法来搜索八数码问题的最优
解。通过输入大量的初始状态和目标状态发现,在一般情 况下都可以找到最优的动作序列,但对某些复杂的初始状 态虽能得到正确解却不能完全得到最短的搜索路径。这
是有待改进的地方。
int result=0:
f or(i=0;i<3;i++)
{ for(j=0;j<3;j++) { XClJl'[cur-->state[i][j]]_i; ycur[cur->state[i][j]]-j; xdest[dest一>state[i][j]]_i;
(上接第31页) 当的优化及处理,可以进一步发挥SVM本身处理问题的 优越性。
表1数据实验结果表
训练集预处理前
训练集预处理后
呵’了
实际结果 预测结果 总耗时(s) 实际结果 预测结果 总耗时(s)
1
+l
+l
+lLeabharlann +12+13
+1
4
+1
5
+1
6
一l
7
一l
8
—1
9
—1
+1 +1 +l +l ‘1’ +1。 —1 —1
pmbldn.Then it"笔xplains the definition of algorithm A*and makes it clear how to impmve the efficiency of search and describe the Go—
rithm A。which is one of heuristic search based On graphsearch.According tO this algorithm display the process of exploring the Eight—
基于A星算法的8数码问题求解方案设计(1)
基于A星算法的8数码问题求解⽅案设计(1)⼀、问题描述8数码问题⼜称9宫问题,与游戏“华容道”类似。
意在给定的33棋格的8个格⼦内分别放⼀个符号,符号之间互不相同,余下的⼀格为空格。
并且通常把8个符号在棋格上的排列顺序称作8数码的状态。
开始时,规则给定⼀个初始状态和⼀个⽬标状态,并要求被试者对棋格内的符号经过若⼲次移动由初始状态达到⽬标状态,这个过程中只有空格附近的符号可以朝空格的⽅向移动,且每次只能移动⼀个符号。
为⽅便编程和表⽰,本⽂中8个格⼦内的符号分别取1—8的8个数字表⽰,空格⽤0表⽰。
并给定8数码的初始状态和⽬标状态分别如图1、2所⽰。
图1 初始状态图2 ⽬标状态则要求以图1为初始状态,通过交换0和0的上、下、左、右四个⽅位的数字(每次只能和其中⼀个交换),达到图2所⽰⽬标状态。
⼆、实验⽬的熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利⽤A*算法求解N数码难题,理解求解流程和搜索顺序。
三、实验任务1)实现类似于如图所⽰N数码难题演⽰程序。
2)⽤你所熟悉的程序语⾔实现,可以B/S实现,也可以C/S实现四、算法设计根据任务要求,本⽂采⽤A*搜索算法。
但要在计算机上通过编程解决该问题,还应当解决该问题在计算机上表⽰的⽅式,并设计合适的启发函数,以提⾼搜索效率。
①状态的表⽰在A*算法中,需要⽤到open表和closed表,特别是在open表中,待扩展节点间有很严格的扩展顺序。
因此在表⽰当前状态的变量中,必须要有能指向下⼀个扩展节点的指针,以完成对open表中元素的索引。
从这⼀点上看,open表中的元素相互间即构成了⼀个线性表,因此初步选定使⽤结构体表⽰问题的状态。
如图3所⽰,表⽰问题的结构体包括表⽰当前节点状态的DATA和指向open 表中下⼀个待扩展节点的指针NEXT。
图3 结构体现在进⼀步考虑DATA中包括的内容:如图1、2所⽰,8数码问题的提出是以⼀个33数表表⽰的,因此本⽂中采⽤⼀个33的⼆维数组s[3][3]表⽰当前状态的具体信息。
A-star-算法-八数码问题-C++-报告+代码+详细注释1
二、程序运行测试A*算法求解八数码问题一、详细设计说明1.评价函数以当前状态下各将牌到目标位置的距离之和作为节点的评价标准。
距离的定义为: “某将牌行下标与目标位置行下标之差的绝对值 + 列下标与目标位置列下标之差的绝对值”。
距离越小, 该节点的效果越好。
某个状态所有将牌到目标位置的距离之和用“h值”表示。
2.主要函数2.1countH(state & st);countH函数功能是计算st状态的h值。
2.2计算过程中将会用到rightPos数组, 数组里记录的是目标状态下, 0~9每个将牌在九宫格里的位置(位置 = 行下标 * 3 + 列下标)。
2.3f(state * p);f()=h()+level2.4look_up_dup(vector<state*> & vec, state * p);2.5在open表或close表中, 是否存在指定状态p, 当找到与p完全相等的节点时, 退出函数。
2.6search(state & start);在open表不为空时, 按f值由小到大对open表中元素进行排序。
调用findZero()函数找到0值元素的位置。
空格可以向上下左右四个方向移动, 前提是移动后不能越过九宫格的边界线。
确定某方向可走后, 空格移动一步, 生成状态p’。
2.7此时, 检查open表中是否已有p’, 若有, 更新p’数据;检查close表中是否已有p’, 若有, 将p’从close表中删除, 添加到open表中。
2.8重复的执行这个过程, 直到某状态的h值为零。
2.9dump_solution(state * q);在终端输出解路径。
// A*算法八数码问题#include"stdafx.h"#include<iostream>#include<vector>#include<time.h>#include<algorithm>using namespace std;const int GRID = 3; //Grid表示表格的行数(列数), 这是3*3的九宫格int rightPos[9] = { 4, 0, 1, 2, 5, 8, 7, 6, 3 };//目标状态时, 若p[i][j]=OMG,那么3*i+j = rightPos[OMG]struct state{int panel[GRID][GRID];int level; //记录深度int h;state * parent;state(int level) :level(level){}bool operator == (state & q){//判断两个状态是否完全相等(对应位置元素相等), 完全相等返回true,否则返回falsefor (int i = 0; i<GRID; i++){for (int j = 0; j<GRID; j++){if (panel[i][j] != q.panel[i][j])return false;}}return true;}state & operator = (state & p){ //以状态p为当前状态赋值, 对应位置元素相同for (int i = 0; i<GRID; i++){for (int j = 0; j<GRID; j++){panel[i][j] = p.panel[i][j];}}return *this;}};void dump_panel(state * p){ //将八数码按3*3矩阵形式输出for (int i = 0; i<GRID; i++){for (int j = 0; j<GRID; j++)cout << p->panel[i][j] << " ";cout << endl;}}int countH(state & st){ //给定状态st, 计算它的h值。
人工智能A星算法解决八数码难题程序代码
#include "Stdio.h"#include "Conio.h"#include "stdlib.h"#include "math.h"void Copy_node(struct node *p1,struct node *p2);void Calculate_f(int deepth,struct node *p);void Add_to_open(struct node *p);void Add_to_closed(struct node *p);void Remove_p(struct node *name,struct node *p);int Test_A_B(struct node *p1,struct node *p2);struct node * Search_A(struct node *name,struct node *temp); void Print_result(struct node *p);struct node // 定义8数码的节点状态{int s[3][3]; //当前8数码的状态int i_0; //当前空格所在行号int j_0; //当前空格所在列号int f; //当前代价值int d; //当前节点深度int h; //启发信息,采用数码"不在位"距离和struct node *father; //指向解路径上该节点的父节点struct node *next; //指向所在open或closed表中的下一个元素} ;struct node s_0={{2,8,3,1,6,4,7,0,5},2,1,0,0,0,NULL,NULL}; //定义初始状态struct node s_g={{1,2,3,8,0,4,7,6,5},1,1,0,0,0,NULL,NULL}; //定义目标状态struct node *open=NULL; //建立open表指针struct node *closed=NULL; //建立closed表指针int sum_node=0; //用于记录扩展节点总数//***********************************************************//********************** **********************//********************** 主函数开始**********************//********************** **********************//***********************************************************void main(){int bingo=0; //定义查找成功标志,bingo=1,成功struct node s; //定义头结点sstruct node *target,*n,*ls,*temp,*same; //定义结构体指针Copy_node(&s_0,&s); //复制初始状s_0态给头结点s Calculate_f(0,&s); //计算头结点的代价值Add_to_open(&s); //将头结点s放入open表while(open!=NULL) //只要open表不为空,进行以下循环{n=open; //n指向open表中当前要扩展的元素ls=open->next;Add_to_closed(n);open=ls; //将n指向的节点放入closed表中if(Test_A_B(n,&s_g)) //当前n指向节点为目标时,跳出程序结束;否则,继续下面的步骤{bingo=1;break;}elseif(n->j_0>=1) //空格所在列号不小于1,可左移{temp=n->father;if(temp!=NULL&&temp->i_0==n->i_0&&temp->j_0-1==n->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(n,temp); //拷贝n指向的节点状态temp->s[temp->i_0][temp->j_0]=temp->s[temp->i_0][temp->j_0-1]; //空格左移temp->s[temp->i_0][temp->j_0-1]=0;temp->j_0--;temp->d++;Calculate_f(temp->d,temp); //修改新节点的代价值temp->father=n; //新节点指向其父节点if(same=Search_A(closed,temp)) //在closed表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比closed表中相同状态节点代价小,加入open表{Remove_p(closed,same); //从closed表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else;}else if(same=Search_A(open,temp)) //在open表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比open表中相同状态节点代价小,加入open表{Remove_p(open,same); //从open表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else ;}else //新节点为完全不同的新节点,加入open表{Add_to_open(temp);sum_node++;}}}//end左移if(n->j_0<=1) //空格所在列号不大于1,可右移{temp=n->father;if(temp!=NULL&&temp->i_0==n->i_0&&temp->j_0+1==n->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(n,temp); //拷贝p指向的节点状态temp->s[temp->i_0][temp->j_0]=temp->s[temp->i_0][temp->j_0+1]; //空格右移temp->s[temp->i_0][temp->j_0+1]=0;temp->j_0++;temp->d++;Calculate_f(temp->d,temp); //修改新节点的代价值temp->father=n; //新节点指向其父节点if(same=Search_A(closed,temp)) //在closed表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比closed表中相同状态节点代价小,加入open表{Remove_p(closed,same); //从closed表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else;}else if(same=Search_A(open,temp)) //在open表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比open表中相同状态节点代价小,加入open表{Remove_p(open,same); //从open表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else ;}else //新节点为完全不同的新节点,加入open表{Add_to_open(temp);sum_node++;}}}//end右移if(n->i_0>=1) //空格所在列号不小于1,上移{temp=n->father;if(temp!=NULL&&temp->i_0==n->i_0-1&&temp->j_0==n->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(n,temp); //拷贝p指向的节点状态temp->s[temp->i_0][temp->j_0]=temp->s[temp->i_0-1][temp->j_0];//空格上移temp->s[temp->i_0-1][temp->j_0]=0;temp->i_0--;temp->d++;Calculate_f(temp->d,temp); //修改新节点的代价值temp->father=n; //新节点指向其父节点if(same=Search_A(closed,temp)) //在closed表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比closed表中相同状态节点代价小,加入open表{Remove_p(closed,same); //从closed表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else;}else if(same=Search_A(open,temp)) //在open表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比open表中相同状态节点代价小,加入open表{Remove_p(open,same); //从open表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else ;}else //新节点为完全不同的新节点,加入open表{Add_to_open(temp);sum_node++;}}}//end上移if(n->i_0<=1) //空格所在列号不大于1,下移{temp=n->father;if(temp!=NULL&&temp->i_0==n->i_0+1&&temp->j_0==n->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(n,temp); //拷贝p指向的节点状态temp->s[temp->i_0][temp->j_0]=temp->s[temp->i_0+1][temp->j_0]; //空格下移temp->s[temp->i_0+1][temp->j_0]=0;temp->i_0++;temp->d++;Calculate_f(temp->d,temp); //修改新节点的代价值temp->father=n; //新节点指向其父节点if(same=Search_A(closed,temp)) //在closed表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比closed表中相同状态节点代价小,加入open表{Remove_p(closed,same); //从closed表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else;}else if(same=Search_A(open,temp)) //在open表中找到与新节点状态相同的节点{if(temp->f<same->f) //temp指向的节点,其代价比open表中相同状态节点代价小,加入open表{Remove_p(open,same); //从open表中删除与temp指向节点状态相同的节点Add_to_open(temp);sum_node++;}else ;}else //新节点为完全不同的新节点,加入open表{Add_to_open(temp);sum_node++;}}}//end下移}if(bingo=1) Print_result(n); //输出解路径else printf("问题求解失败!");}//主函数结束//************************************************************************* //********************** ********************** //********************** 计算某个节点状态的代价值********************** //********************** ********************** //*************************************************************************void Calculate_f(int deepth,struct node *p){int i,j,temp;temp=0;for(i=0;i<=2;i++) //计算所有"不在位"数码的距离和{for(j=0;j<=2;j++){if((p->s[i][j])!=(s_g.s[i][j]))temp++;}}p->h=temp;p->f=deepth+p->h;}//*************************************************************************//********************** **********************//********************** 添加p指向的节点到open表中********************** //********************** **********************//*************************************************************************void Add_to_open(struct node *p){struct node *p1,*p2;p1=open; //初始时p1指向open表首部p2=NULL;if(open==NULL) //open表为空时,待插入节点即为open表第一个元素,open 指向该元素{p->next=NULL;open=p;}else //open表不为空时,添加待插入节点,并保证open表代价递增的排序{while(p1!=NULL&&p->f>p1->f){p2=p1; //p2始终指向p1指向的前一个元素p1=p1->next;}if(p2==NULL) //待插入节点为当前open表最小{p->next=open;open=p;}else if(p1==NULL) //待插入节点为当前open表最大{p->next=NULL;p2->next=p;}else //待插入节点介于p2、p1之间{p2->next=p;p->next=p1;}}}//***************************************************************************//********************** **********************//********************** 添加p指向的节点到closed表中**********************//********************** **********************//***************************************************************************void Add_to_closed(struct node *p){if(closed==NULL) //closed表为空时,p指向节点为closed表第一个元素,closed{p->next=NULL;closed=p;}else //closed表不为空时,直接放到closed表首部{p->next=closed;closed=p;}}//************************************************************************************* *************//********************************************//********************** 在open表或closed表中搜索和temp指向的节点相同的节点**********************//********************************************//*************************************************************************************struct node * Search_A(struct node *name,struct node *temp){struct node *p1;p1=name; //p1指向open表或closed表while(p1!=NULL){if(Test_A_B(p1,temp)) //找到相同的节点,返回该节点地址return p1;elsep1=p1->next;}return NULL;}//************************************************************************************* **********//********************************************//********************** 判断两个节点状态是否相同,相同则返回1,否则返回0 **********************//********************************************//************************************************************************************* **********int Test_A_B(struct node *p1,struct node *p2){int i,j,flag;flag=1;for(i=0;i<=2;i++)for(j=0;j<=2;j++){if((p2->s[i][j])!=(p1->s[i][j])) { flag=0; return flag; }else ;}return flag;}//******************************************************************************//********************** **********************//********************** 从open表或closed表删除指定节点********************** //********************** **********************//******************************************************************************void Remove_p(struct node *name,struct node *p){struct node *p1,*p2;p1=NULL;p2=NULL;if(name==NULL) //如果name指向的链表为空,则不需要进行删除return;else if(Test_A_B(name,p)&&name->f==p->f) //指定节点为name指向的链表的第一个元素{open=name->next;name->next=NULL;return;}else{p2=name;p1=p2->next;while(p1){if(Test_A_B(p1,p)&&p1->f==p->f) //找到指定节点{p2->next=p1->next;return;}else{p2=p1; //p2始终指向p1指向的前一个元素p1=p1->next;}}return;}}//************************************************************************************* *//********************************************//********************** 将p1指向的节点状态拷贝到p2指向的节点中**********************//********************************************//************************************************************************************* *void Copy_node(struct node *p1,struct node *p2){int i,j;for(i=0;i<=2;i++){for(j=0;j<=2;j++){ p2->s[i][j]=p1->s[i][j]; }}p2->i_0=p1->i_0;p2->j_0=p1->j_0;p2->f=p1->f;p2->d=p1->d;p2->h=p1->h;p2->next=p1->next;p2->father=p1->father;}//*********************************************************** //********************** ********************** //********************** 输出结果********************** //********************** ********************** //***********************************************************void Print_result(struct node *p){struct node *path[100];struct node *temp,*temp_father;int i,j,k;for(i=0;i<=99;i++) //初始化路径指针数组path[i]=0;temp=p;printf("总共扩展%d 个节点\n",sum_node);printf("总共扩展%d 层\n",temp->d);printf("解路径如下:\n");for(i=p->d;i>=0;i--) //存储解路径上各节点的地址{path[i]=temp;temp=temp->father;}for(k=0;k<=p->d;k++) //输出解路径{temp=path[k]; //建立节点指点指针printf("第%d步",temp->d);if(k-1>=0) //输出移动策略{temp_father=path[k-1];if(temp->i_0<temp_father->i_0) printf("->上移\n");if(temp->i_0>temp_father->i_0) printf("->下移\n");if(temp->j_0<temp_father->j_0) printf("->左移\n");if(temp->j_0>temp_father->j_0) printf("->右移\n");}elseprintf("\n");printf("当前节点状态为:\n");for(i=0;i<=2;i++){for(j=0;j<=2;j++){printf("%d ",temp->s[i][j]);}printf("\n");}printf("\n");}}THANKS !!!致力为企业和个人提供合同协议,策划案计划书,学习课件等等打造全网一站式需求欢迎您的下载,资料仅供参考。
八数码问题源代码
自己用宽度优先算法写的八数码问题,有代码,有注释,有截图中间动态变化过程截图省略……源代码:EightDigital.javapackage eightDigitalProblem;import java.util.*;public class EightDigital {public static void main(String[] args) {// TODO Auto-generated method stub//EightDigital ed = new EightDigital();//unch();MyFrame mf = new MyFrame();unchMyFrame();}public Node launch(int [] startData, int [] endData){//起始结点赋值283164705//结束结点赋值123804765int[] array0 = new int[9];Node s0 = new Node(array0);Node s = new Node(startData);s.setDepth(0);s.setStep(0);s.setFatherNode(s0);LinkedList<Node> open = new LinkedList<Node>(); //open集合open.add(s); //添加初始点LinkedList<Node> closed = new LinkedList<Node>(); //closed集合Node n;while(true){ //循环if(open.isEmpty()){System.out.println("fail");System.exit(0);}n = open.getFirst();if(goal(n, endData)){System.out.println("success"); //找到目标结点了break;}closed.add(n); //把结点加入到closed表中open.removeFirst(); //删除最前面的结点LinkedList<Node> m = expand(n); //扩展结点while(!m.isEmpty()){open.add(m.removeFirst());}}//找到目标结点n.display();return n;}public boolean goal(Node n, int [] endData){int[] array = new int[9];//目标结点赋初值array[0] = 1;array[1] = 2;array[2] = 3;array[3] = 8;array[4] = 0;array[5] = 4;array[6] = 7;array[7] = 6;array[8] = 5;//Node s = new Node(array); //目标结点Node s = new Node(endData); //目标结点if(s.equals(n)){return true;}else{return false;}}public LinkedList<Node> expand(Node n){ //n结点向外扩展,返回扩展的结点集合LinkedList<Node> temp = new LinkedList<Node>();int zeroPosition = n.getZeroPosition(n); //记录0(空格)的位置if(rightMove(zeroPosition)){ //空格可以向右移动Node newNode = new Node(n); //创造一个新结点newNode.getArray()[zeroPosition] = newNode.getArray()[zeroPosition+1]; //空格右移newNode.getArray()[zeroPosition+1] = 0;if( !n.getFatherNode().equals(newNode) ){ //新产生的结点不能是结点n的父节点temp.add(newNode); //将新结点添加到集合newNode.setFatherNode(n); //设置新结点的父结点newNode.setStep(n.getStep()+1); //设置新结点到此走过的步长newNode.setDepth(newNode.getFatherNode().getDepth()+1); //设置深度}}if(leftMove(zeroPosition)){ //空格可以向左移动Node newNode = new Node(n); //创造一个新结点newNode.getArray()[zeroPosition] = newNode.getArray()[zeroPosition-1]; //空格左移newNode.getArray()[zeroPosition-1] = 0;if( !n.getFatherNode().equals(newNode) ){ //新产生的结点不能是结点n的父节点temp.add(newNode); //将新结点添加到集合newNode.setFatherNode(n); //设置新结点的父结点newNode.setStep(n.getStep()+1); //设置新结点到此走过的步长newNode.setDepth(newNode.getFatherNode().getDepth()+1); //设置深度}}if(upMove(zeroPosition)){ //空格可以向上移动Node newNode = new Node(n); //创造一个新结点newNode.getArray()[zeroPosition] = newNode.getArray()[zeroPosition-3]; //空格上移newNode.getArray()[zeroPosition-3] = 0;if( !n.getFatherNode().equals(newNode) ){ //新产生的结点不能是结点n的父节点temp.add(newNode); //将新结点添加到集合newNode.setFatherNode(n); //设置新结点的父结点newNode.setStep(n.getStep()+1); //设置新结点到此走过的步长newNode.setDepth(newNode.getFatherNode().getDepth()+1); //设置深度}}if(downMove(zeroPosition)){ //空格可以向下移动Node newNode = new Node(n); //创造一个新结点newNode.getArray()[zeroPosition] = newNode.getArray()[zeroPosition+3]; //空格下移newNode.getArray()[zeroPosition+3] = 0;if( !n.getFatherNode().equals(newNode) ){ //新产生的结点不能是结点n的父节点temp.add(newNode); //将新结点添加到集合newNode.setFatherNode(n); //设置新结点的父结点newNode.setStep(n.getStep()+1); //设置新结点到此走过的步长newNode.setDepth(newNode.getFatherNode().getDepth()+1); //设置深度}}return temp;}public boolean rightMove(int p){ //判断能否空格能否向右移动if(p%3 == 2){ //第3列不能往右移动了,第3列除以3的余数为2return false;}else{ //第1,2列可以向右移动return true;}}public boolean leftMove(int p){ //判断能否空格能否向左移动if(p%3 == 0){ //第0列不能往左移动了,第1列除以3的余数为0 return false;}else{ //第2,3列可以向左移动return true;}}public boolean upMove(int p){if(p < 3){ //第一行p=0,1,2 不能往上移动了return false;}else{ //第2,3行可以向上移动return true;}}public boolean downMove(int p){if(p > 5){ //第3行p=6,7,8 不能向下移动了return false;}else{ //第1,2行可以向下移动return true;}}public LinkedList<Node> sortByDepth(LinkedList<Node> list){ LinkedList<Node> temp = new LinkedList<Node>();while(!list.isEmpty()){Node deepestNode = list.getFirst();Iterator<Node> ite = list.iterator();while(ite.hasNext()){Node node = ite.next();if(node.getDepth()>deepestNode.getDepth()){deepestNode = node;}}temp.add(deepestNode);list.remove(deepestNode);}return temp;}}MyFrame.javapackage eightDigitalProblem;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.*;import java.awt.*;import java.util.Stack;public class MyFrame extends JFrame implements ActionListener{ private static final long serialVersionUID = 1L;private JMenuBar jmenubar;private JMenu jmenu1;private JMenu jmenu2;private JMenuItem jmenuitem1;private JMenuItem jmenuitem2;private JPanel jpanel1;private JPanel jpanel2;private JPanel jpanel3;private JPanel jpanel4;private JLabel jlabel1; //初始值private JLabel jlabel2; //结束值private JLabel jlabel3; //提示private JLabel jlabel4; //提示private JTextField jtextfield1;private JTextField jtextfield2;private JTextField jtextfield3;private JLabel l1;private JLabel l2;private JLabel l3;private JLabel l4;private JLabel l5;private JLabel l6;private JLabel l7;private JLabel l8;private JLabel l9;private Font font;private Font font2;HelpFrame helpFrame;MyFrame(){jmenubar = new JMenuBar();jmenu1 = new JMenu("选择算法");jmenu2 = new JMenu("帮助");jmenuitem1 = new JMenuItem("宽度优先");jmenuitem2 = new JMenuItem("使用说明");jpanel1 = new JPanel();jpanel2 = new JPanel();jpanel3 = new JPanel();jpanel4 = new JPanel();jlabel1 = new JLabel("初始值:",JLabel.CENTER);jlabel2 = new JLabel("结束值:",JLabel.CENTER);jlabel3 = new JLabel("",JLabel.LEFT); //提示jlabel4 = new JLabel("",JLabel.LEFT); //提示jtextfield1 = new JTextField("283164705");jtextfield2 = new JTextField("123804765");jtextfield3 = new JTextField("步数");jtextfield3.setBackground(new Color(238,238,238));l1 = new JLabel("",JLabel.CENTER);l2 = new JLabel("",JLabel.CENTER);l3 = new JLabel("",JLabel.CENTER);l4 = new JLabel("",JLabel.CENTER);l5 = new JLabel("",JLabel.CENTER);l6 = new JLabel("",JLabel.CENTER);l7 = new JLabel("",JLabel.CENTER);l8 = new JLabel("",JLabel.CENTER);l9 = new JLabel("",JLabel.CENTER);font = new Font(Font.DIALOG,Font.BOLD,22);font2 = new Font(Font.DIALOG,Font.BOLD,14);}public void launchMyFrame(){jmenuitem1.addActionListener(this); jmenuitem2.addActionListener(this);jmenu1.add(jmenuitem1); jmenubar.add(jmenu1);jmenu2.add(jmenuitem2); jmenubar.add(jmenu2);jpanel1.setLayout(new GridLayout(1,2)); jpanel1.add(jlabel1);jpanel1.add(jtextfield1);jpanel2.setLayout(new GridLayout(1,2)); jpanel2.add(jlabel2);jpanel2.add(jtextfield2);jpanel3.setLayout(new GridLayout(3,3)); jpanel3.add(l1);jpanel3.add(l2);jpanel3.add(l3);jpanel3.add(l4);jpanel3.add(l5);jpanel3.add(l6);jpanel3.add(l7);jpanel3.add(l8);jpanel3.add(l9);jpanel4.setLayout(new GridLayout(2,2)); jpanel4.add(jpanel1);jpanel4.add(jlabel3);jpanel4.add(jpanel2);jpanel4.add(jlabel4);//设置字体l1.setFont(font);l2.setFont(font);l3.setFont(font);l4.setFont(font);l5.setFont(font);l6.setFont(font);l7.setFont(font);l8.setFont(font);l9.setFont(font);jtextfield3.setFont(font2);this.setLayout(new BorderLayout());this.add(jpanel4,BorderLayout.NORTH); //上面this.add(jpanel3,BorderLayout.CENTER); //中间this.add(jtextfield3,BorderLayout.SOUTH); //下面setJMenuBar(jmenubar);setSize(330,350); //设置大小setLocation(510,180); //设置位置setTitle("EightDigital"); //设置标题setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setVisible(true); //设为可见}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubObject source=e.getSource();if(source == jmenuitem1){boolean flag = true;EightDigital ed;int [] array1 = new int[9];int [] array2 = new int[9];int attribute = 0; //逆序数的奇偶性0-偶1-奇int reNum; //逆序数String startData = jtextfield1.getText().trim();if(startData.length() != 9){ //长度必须为9jlabel3.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else if(!isNumber(startData)){ //每个都必须是数字0-8 jlabel3.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else{jlabel3.setText("");for(int i=0; i<9; i++){ //将startData转化为整数数组Character c = startData.charAt(i);array1[i] = Integer.parseInt(c.toString());}if(repeatNum(array1)){flag = false;jlabel3.setText("有重复的数字!");jpanel3.setVisible(false);}else{reNum = reverseNum(array1);jlabel3.setText("逆序数:" + reNum);attribute = reNum%2; //0-偶1-奇}}String endData = jtextfield2.getText().trim();if(endData.length() != 9){ //长度必须为9jlabel4.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else if(!isNumber(endData)){ //每个都必须是数字0-8jlabel4.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else{jlabel4.setText("");for(int i=0; i<9; i++){ //将startData转化为整数数组Character c = endData.charAt(i);array2[i] = Integer.parseInt(c.toString());}if(repeatNum(array2)){flag = false;jlabel4.setText("有重复的数字!");jpanel3.setVisible(false);}else{reNum = reverseNum(array2);jlabel4.setText("逆序数:" + reNum);if(reNum%2 != attribute){ //两个逆序数的奇偶性不一致flag = false;jlabel4.setText("逆序数:" + reNum + " " + "奇偶不一致");jpanel3.setVisible(false);}}}if(flag){ed = new EightDigital();jpanel3.setVisible(true);showProcess(unch(array1,array2));}}else if(source == jmenuitem2){helpFrame = new HelpFrame();unchHelpFrame();}}public boolean isNumber(String data){ //判断是否是数字0-8char[] array = data.toCharArray();boolean flag = true;int temp;for(char c : array){//flag = Character.isDigit(c); //判断是否为数字if(flag = Character.isDigit(c)){Character ch = c;temp = Integer.parseInt(ch.toString());if(temp == 9){flag = false;}}if(flag == false){break;}}System.out.println("flag = " + flag); //testreturn flag;}public boolean repeatNum(int[] array){ //判断是否有重复的数字boolean flag = false;int[] temp = new int[array.length];for(int i:array){temp[i] = 1; //有数字的地方标记为1}for(int j:temp){if(j==0){flag = true; //有一个数字没有出现}}return flag;}public void showProcess(final Node n){ //展示搜索过程new Thread(new Runnable(){@Overridepublic void run() {// TODO Auto-generated method stubStack<Node> stack = new Stack<Node>();Node fatherNode = n.getFatherNode();stack.add(n);while(fatherNode != null){stack.add(fatherNode); //入栈fatherNode = fatherNode.getFatherNode();}stack.pop();while(!stack.isEmpty()){ //从栈中去结点Node cnode = stack.pop();int [] array = cnode.getArray();l1.setText(array[0]+"");l2.setText(array[1]+"");l3.setText(array[2]+"");l4.setText(array[3]+"");l5.setText(array[4]+"");l6.setText(array[5]+"");l7.setText(array[6]+"");l8.setText(array[7]+"");l9.setText(array[8]+"");jtextfield3.setText("第" + cnode.getStep() + "步"); //显示步数try{Thread.sleep(2000); //暂停一会}catch(Exception e){e.printStackTrace();}}}}).start();}public int reverseNum(int[] array){ //求逆序数int num = 0;for(int i=0; i<array.length-1; i++){for(int j=i+1; j<array.length; j++){if(array[i]>0 && array[j]>0 && array[i]>array[j]){num++;}}}return num;}}Node.javapackage eightDigitalProblem;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.*;import java.awt.*;import java.util.Stack;public class MyFrame extends JFrame implements ActionListener{ private static final long serialVersionUID = 1L;private JMenuBar jmenubar;private JMenu jmenu1;private JMenu jmenu2;private JMenuItem jmenuitem1;private JMenuItem jmenuitem2;private JPanel jpanel1;private JPanel jpanel2;private JPanel jpanel3;private JPanel jpanel4;private JLabel jlabel1; //初始值private JLabel jlabel2; //结束值private JLabel jlabel3; //提示private JLabel jlabel4; //提示private JTextField jtextfield1;private JTextField jtextfield2;private JTextField jtextfield3;private JLabel l1;private JLabel l2;private JLabel l3;private JLabel l4;private JLabel l5;private JLabel l6;private JLabel l7;private JLabel l8;private JLabel l9;private Font font;private Font font2;HelpFrame helpFrame;MyFrame(){jmenubar = new JMenuBar();jmenu1 = new JMenu("选择算法");jmenu2 = new JMenu("帮助");jmenuitem1 = new JMenuItem("宽度优先");jmenuitem2 = new JMenuItem("使用说明");jpanel1 = new JPanel();jpanel2 = new JPanel();jpanel3 = new JPanel();jpanel4 = new JPanel();jlabel1 = new JLabel("初始值:",JLabel.CENTER);jlabel2 = new JLabel("结束值:",JLabel.CENTER);jlabel3 = new JLabel("",JLabel.LEFT); //提示jlabel4 = new JLabel("",JLabel.LEFT); //提示jtextfield1 = new JTextField("283164705");jtextfield2 = new JTextField("123804765");jtextfield3 = new JTextField("步数");jtextfield3.setBackground(new Color(238,238,238));l1 = new JLabel("",JLabel.CENTER);l2 = new JLabel("",JLabel.CENTER);l3 = new JLabel("",JLabel.CENTER);l4 = new JLabel("",JLabel.CENTER);l5 = new JLabel("",JLabel.CENTER);l6 = new JLabel("",JLabel.CENTER);l7 = new JLabel("",JLabel.CENTER);l8 = new JLabel("",JLabel.CENTER);l9 = new JLabel("",JLabel.CENTER);font = new Font(Font.DIALOG,Font.BOLD,22);font2 = new Font(Font.DIALOG,Font.BOLD,14); }public void launchMyFrame(){jmenuitem1.addActionListener(this);jmenuitem2.addActionListener(this);jmenu1.add(jmenuitem1);jmenubar.add(jmenu1);jmenu2.add(jmenuitem2);jmenubar.add(jmenu2);jpanel1.setLayout(new GridLayout(1,2));jpanel1.add(jlabel1);jpanel1.add(jtextfield1);jpanel2.setLayout(new GridLayout(1,2));jpanel2.add(jlabel2);jpanel2.add(jtextfield2);jpanel3.setLayout(new GridLayout(3,3));jpanel3.add(l1);jpanel3.add(l2);jpanel3.add(l3);jpanel3.add(l4);jpanel3.add(l5);jpanel3.add(l6);jpanel3.add(l7);jpanel3.add(l8);jpanel3.add(l9);jpanel4.setLayout(new GridLayout(2,2));jpanel4.add(jpanel1);jpanel4.add(jlabel3);jpanel4.add(jpanel2);jpanel4.add(jlabel4);//设置字体l1.setFont(font);l2.setFont(font);l3.setFont(font);l4.setFont(font);l5.setFont(font);l6.setFont(font);l7.setFont(font);l8.setFont(font);l9.setFont(font);jtextfield3.setFont(font2);this.setLayout(new BorderLayout());this.add(jpanel4,BorderLayout.NORTH); //上面this.add(jpanel3,BorderLayout.CENTER); //中间this.add(jtextfield3,BorderLayout.SOUTH); //下面setJMenuBar(jmenubar);setSize(330,350); //设置大小setLocation(510,180); //设置位置setTitle("EightDigital"); //设置标题setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setVisible(true); //设为可见}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubObject source=e.getSource();if(source == jmenuitem1){boolean flag = true;EightDigital ed;int [] array1 = new int[9];int [] array2 = new int[9];int attribute = 0; //逆序数的奇偶性0-偶1-奇int reNum; //逆序数String startData = jtextfield1.getText().trim();if(startData.length() != 9){ //长度必须为9jlabel3.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else if(!isNumber(startData)){ //每个都必须是数字0-8 jlabel3.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else{jlabel3.setText("");for(int i=0; i<9; i++){ //将startData转化为整数数组Character c = startData.charAt(i);array1[i] = Integer.parseInt(c.toString());}if(repeatNum(array1)){flag = false;jlabel3.setText("有重复的数字!");jpanel3.setVisible(false);}else{reNum = reverseNum(array1);jlabel3.setText("逆序数:" + reNum);attribute = reNum%2; //0-偶1-奇}}String endData = jtextfield2.getText().trim();if(endData.length() != 9){ //长度必须为9jlabel4.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else if(!isNumber(endData)){ //每个都必须是数字0-8 jlabel4.setText("请输入0-8的一个排列!");flag = false;jpanel3.setVisible(false);}else{jlabel4.setText("");for(int i=0; i<9; i++){ //将startData转化为整数数组Character c = endData.charAt(i);array2[i] = Integer.parseInt(c.toString());}if(repeatNum(array2)){flag = false;jlabel4.setText("有重复的数字!");jpanel3.setVisible(false);}else{reNum = reverseNum(array2);jlabel4.setText("逆序数:" + reNum);if(reNum%2 != attribute){ //两个逆序数的奇偶性不一致flag = false;jlabel4.setText("逆序数:" + reNum + " " + "奇偶不一致");jpanel3.setVisible(false);}}}if(flag){ed = new EightDigital();jpanel3.setVisible(true);showProcess(unch(array1,array2));}}else if(source == jmenuitem2){helpFrame = new HelpFrame();unchHelpFrame();}}public boolean isNumber(String data){ //判断是否是数字0-8char[] array = data.toCharArray();boolean flag = true;int temp;for(char c : array){//flag = Character.isDigit(c); //判断是否为数字if(flag = Character.isDigit(c)){Character ch = c;temp = Integer.parseInt(ch.toString());if(temp == 9){flag = false;}}if(flag == false){break;}}System.out.println("flag = " + flag); //testreturn flag;}public boolean repeatNum(int[] array){ //判断是否有重复的数字boolean flag = false;int[] temp = new int[array.length];for(int i:array){temp[i] = 1; //有数字的地方标记为1}for(int j:temp){if(j==0){flag = true; //有一个数字没有出现}}return flag;}public void showProcess(final Node n){ //展示搜索过程new Thread(new Runnable(){@Overridepublic void run() {// TODO Auto-generated method stubStack<Node> stack = new Stack<Node>();Node fatherNode = n.getFatherNode();stack.add(n);while(fatherNode != null){stack.add(fatherNode); //入栈fatherNode = fatherNode.getFatherNode();}stack.pop();while(!stack.isEmpty()){ //从栈中去结点Node cnode = stack.pop();int [] array = cnode.getArray();l1.setText(array[0]+"");l2.setText(array[1]+"");l3.setText(array[2]+"");l4.setText(array[3]+"");l5.setText(array[4]+"");l6.setText(array[5]+"");l7.setText(array[6]+"");l8.setText(array[7]+"");l9.setText(array[8]+"");jtextfield3.setText("第" + cnode.getStep() + "步"); //显示步数try{Thread.sleep(2000); //暂停一会}catch(Exception e){e.printStackTrace();}}}}).start();}public int reverseNum(int[] array){ //求逆序数int num = 0;for(int i=0; i<array.length-1; i++){for(int j=i+1; j<array.length; j++){if(array[i]>0 && array[j]>0 && array[i]>array[j]){num++;}}}return num;}}HelpFrame.javapackage eightDigitalProblem;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.*;import java.awt.*;public class HelpFrame extends JFrame implements ActionListener{21private static final long serialVersionUID = 1L;private JTextArea jta;private String str1;private Dimension dimension1;//private String str2;HelpFrame(){jta= new JTextArea();dimension1 = new Dimension(290,290);jta.setPreferredSize(dimension1);jta.setBackground(new Color(238,238,238));str1 = "由于要实现在没有jvm的电脑上运行,搜索环境变量与\r\n";str1 = "操作步骤:\r\n" +"1.输入初始值(0-8的任意一个排列);\r\n" +"2.输入结束值(0-8的任意一个排列);\r\n" +"3.点击“选择算法”;\r\n" +"4.点击“宽度优先”;\r\n\r\n" +"注意事项:\r\n" +"1.初始值和结束值都必须是0-8的任意一个排列;\r\n" +"2.初始值的逆序数和结束值的逆序数奇偶性要一致;\r\n";//str2 = "使用说明xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";}public void launchHelpFrame(){//jtf.setText(str1+"\r\n"+str2);jta.setText(str1);jta.setEditable(false);this.setLayout(new FlowLayout());this.add(jta);this.setTitle("使用说明");this.setSize(330,350);this.setLocation(880, 180);this.setVisible(true);}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stub22//Object source = e.getSource();}}23。
用A算法解决八数码问题
用A*算法解决八数码问题一、 题目:八数码问题也称为九宫问题。
在3×3的棋盘,有八个棋子,每个棋子上标有1至8的某一数字,分歧棋子上标的数字不相同。
棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。
要解决的问题是:任意给出一个初始状态和一个目标状态,找出一种从初始转酿成目标状态的移动棋子步数最少的移动步调。
二、 问题的搜索形式描述状态:状态描述了8个棋子和空位在棋盘的9个方格上的分布。
初始状态:任何状态都可以被指定为初始状态。
操纵符:用来发生4个行动(上下左右移动)。
目标测试:用来检测状态是否能匹配上图的目标规划。
路径费用函数:每一步的费用为1,因此整个路径的费用是路径中的步数。
现在任意给定一个初始状态,要求找到一种搜索战略,用尽可能少的步数得到上图的目标状态算法介绍三、解决方案介绍1.A*算法的一般介绍A*(A-Star)算法是一种静态路网中求解最短路最有效的方法。
对于几何路网来说,可以取两节点间欧几理德距离(直线距离)做为估价值,即 ()()()()()()**f g n sqrt dx nx dx nx dy ny dy ny =+--+--;这样估价函数f 在g 值一定的情况下,会或多或少的受估价值h 的制约,节点距目标点近,h 值小,f 值相对就小,能包管最短路的搜索向终点的方向进行。
明显优于盲目搜索战略。
A star 算法在静态路网中的应用2.算法伪代码创建两个表,OPEN 表保管所有已生成而未考察的节点,CLOSED 表中记录已访问过的节点。
算起点的估价值,将起点放入OPEN 表。
while(OPEN!=NULL){从OPEN表中取估价值f最小的节点n;if(n节点==目标节点){break;}for(当前节点n 的每个子节点X){算X的估价值;if(X in OPEN){if( X的估价值小于OPEN表的估价值){把n设置为X的父亲;更新OPEN表中的估价值; //取最小路径的估价值}}if(X inCLOSE){if( X的估价值小于CLOSE表的估价值){把n设置为X的父亲;更新CLOSE表中的估价值;把X节点放入OPEN //取最小路径的估价值}}if(X not inboth){把n设置为X的父亲;求X的估价值;并将X拔出OPEN表中; //还没有排序}}//end for将n节点拔出CLOSE表中;依照估价值将OPEN表中的节点排序; //实际上是比较OPEN表内节点f的大小,从最小路径的节点向下进行。
八数码C语言A算法详细代码
八数码C语言A算法详细代码以下是八数码问题的C语言A*算法的详细代码:```c#include <stdio.h>#include <stdlib.h>#define N 3typedef struct Nodeint board[N][N]; // 八数码局面struct Node *parent; // 父节点指针int f; // f(n) = g(n) + h(n),g(n)表示起始节点到当前节点的代价,h(n)表示当前节点到目标节点的估计代价int g; // g(n)int h; // h(n)} Node;//目标局面int target[N][N] = {{1, 2, 3}, {8, 0 ,4}, {7, 6, 5}};//计算当前节点到目标节点的曼哈顿距离int manhattanDistance(int board[N][N])int distance = 0;for (int i = 0; i < N; i++)for (int j = 0; j < N; j++)if (board[i][j] != 0)int value = board[i][j] - 1;int targetI = value / N;int targetJ = value % N;distance += abs(i - targetI) + abs(j - targetJ);}}}return distance;//创建一个新节点Node* createNode(int board[N][N], int g, Node* parent) Node* node = (Node*) malloc(sizeof(Node));for (int i = 0; i < N; i++)for (int j = 0; j < N; j++)node->board[i][j] = board[i][j];}}node->parent = parent;node->g = g;node->h = manhattanDistance(board);node->f = node->g + node->h;return node;//判断两个局面是否相等int isBoardEqual(int board1[N][N], int board2[N][N]) for (int i = 0; i < N; i++)for (int j = 0; j < N; j++)if (board1[i][j] != board2[i][j])return 0;}}}return 1;//判断节点是否在开放列表中int isInOpenList(Node *node, Node **openList, int openListSize)for (int i = 0; i < openListSize; i++)if (isBoardEqual(node->board, openList[i]->board))return 1;}}return 0;//判断节点是否在关闭列表中int isInClosedList(Node *node, Node **closedList, int closedListSize)for (int i = 0; i < closedListSize; i++)if (isBoardEqual(node->board, closedList[i]->board))return 1;}}return 0;//比较两个节点的f(n)值Node *a = *(Node **)node1;Node *b = *(Node **)node2;return a->f - b->f;//输出路径void printPath(Node *node)if (node != NULL)printPath(node->parent);printf("Step %d:\n", node->g);for (int i = 0; i < N; i++)printf("%d %d %d\n", node->board[i][0], node->board[i][1], node->board[i][2]);}printf("\n");}//A*算法求解八数码问题void solvePuzzle(int initial[N][N])//创建初始节点Node* initialNode = createNode(initial, 0, NULL);//开放列表和关闭列表Node* openList[N*N*N*N];int openListSize = 0;Node* closedList[N*N*N*N];int closedListSize = 0;//将初始节点放入开放列表openList[openListSize++] = initialNode;while (openListSize > 0)//从开放列表中选择f(n)最小的节点//取出开放列表中f(n)最小的节点作为当前节点Node* currentNode = openList[0];//将当前节点从开放列表中移除for (int i = 1; i < openListSize; i++) openList[i - 1] = openList[i];}openListSize--;//将当前节点放入关闭列表closedList[closedListSize++] = currentNode; //判断当前节点是否为目标节点if (isBoardEqual(currentNode->board, target)) printf("Solution found!\n");printPath(currentNode);return;}//生成当前节点的邻居节点int i = 0, j = 0;for (i = 0; i < N; i++)for (j = 0; j < N; j++)if (currentNode->board[i][j] == 0)break;}}if (j < N)break;}}if (i > 0)int newBoard[N][N];for (int k = 0; k < N; k++)for (int l = 0; l < N; l++)newBoard[k][l] = currentNode->board[k][l]; }}newBoard[i][j] = newBoard[i - 1][j];newBoard[i - 1][j] = 0;if (!isInOpenList(createNode(newBoard, currentNode->g + 1, currentNode), openList, openListSize) &&!isInClosedList(createNode(newBoard, currentNode->g + 1, currentNode), closedList, closedListSize))openList[openListSize++] = createNode(newBoard, currentNode->g + 1, currentNode);}}if (i < N - 1)int newBoard[N][N];for (int k = 0; k < N; k++)for (int l = 0; l < N; l++)newBoard[k][l] = currentNode->board[k][l];}}newBoard[i][j] = newBoard[i + 1][j];newBoard[i + 1][j] = 0;currentNode), openList, openListSize) &&!isInClosedList(createNode(newBoard, currentNode->g + 1, currentNode), closedList, closedListSize))openList[openListSize++] = createNode(newBoard, currentNode->g + 1, currentNode);}}if (j > 0)int newBoard[N][N];for (int k = 0; k < N; k++)for (int l = 0; l < N; l++)newBoard[k][l] = currentNode->board[k][l];}}newBoard[i][j] = newBoard[i][j - 1];newBoard[i][j - 1] = 0;if (!isInOpenList(createNode(newBoard, currentNode->g + 1, currentNode), openList, openListSize) &¤tNode), closedList, closedListSize))openList[openListSize++] = createNode(newBoard, currentNode->g + 1, currentNode);}}if (j < N - 1)int newBoard[N][N];for (int k = 0; k < N; k++)for (int l = 0; l < N; l++)newBoard[k][l] = currentNode->board[k][l];}}newBoard[i][j] = newBoard[i][j + 1];newBoard[i][j + 1] = 0;if (!isInOpenList(createNode(newBoard, currentNode->g + 1, currentNode), openList, openListSize) &&!isInClosedList(createNode(newBoard, currentNode->g + 1, currentNode), closedList, closedListSize))openList[openListSize++] = createNode(newBoard, currentNode->g + 1, currentNode);}}}printf("Solution not found!\n");int maiint initial[N][N] = {{2, 8, 3}, {1, 6, 4}, {7, 0, 5}};solvePuzzle(initial);return 0;```这个代码实现了八数码问题的A*算法。
A星算法实现八数码问题的代码 c++实现 可以直接编译运行
*文件Chess.h,包含必要的数据结构,全局变量和类声明*/#ifndef _YLQ_CHESS_#define _YLQ_CHESS_#include <algorithm>#include <iostream>#include <vector>#ifndef N#define N 3#endif#define BLANK 0static int g_iId=1;typedef struct tagNode{int node[N][N];int iF,iH,iG;int id,idParent;}NODE,*PNODE;typedef std::vector<NODE> OPEN;#define CLOSED OPEN#define SUCCERSSOR OPENclass Chess{public:Chess(NODE const &nstar,NODE const &nend); private:OPEN m_vOpen,m_vClosed;NODE m_nStart,m_nEnd;bool NodeEuqal(NODE node1,NODE node2);bool NodeExist(NODE node);bool InOpen(NODE node,int &index);bool InClose(NODE node,int &index);SUCCERSSOR ExplortNode(NODE node); protected:virtual int CaculateHV(NODE &node);//计算h值和f值public:bool Algorithms();void Show(int it);//it=1展示Open,2->Closed};#endif*文件Chess.cpp,包含算法实现*/#include "Chess.h"#include <MA TH.H>bool comp(const NODE &n1,const NODE &n2){return n1.iF>n2.iF;}void Chess::Show(int tp){SUCCERSSOR::iterator it,iend;if (tp==1) {it=m_vOpen.begin();iend=m_vOpen.end();}else{it=m_vClosed.begin();iend=m_vClosed.end();}for (;it!=iend;it++){printf("iF=%d;iG=%d;iH=%d\n",(PNODE)it->iF,(PNODE)it->iG,(PNODE)it->iH);printf("id=%d;idParent=%d\n",(PNODE)it->id,(PNODE)it->idParent);for(int i=0;i<N;i++){for (int j=0;j<N;j++){printf("%d ",(PNODE)it->node[i][j]);}std::cout<<std::endl;}}}Chess::Chess(const NODE &nstar,const NODE &nend){m_nStart = nstar;m_nEnd = nend;m_nStart.idParent=0;//初始结点的父节点设为0m_nStart.id = 1;m_nStart.iG=0;//初始结点G设为0,再次结点扩展一次就+1( 表示深度);CaculateHV(m_nStart);//初始化开始结点h和f以及gm_vOpen.push_back(m_nStart);}int Chess::CaculateHV(NODE &node){//用位置差来计算h值node.iH=0;for (int i=0;i<N;i++){for (int j=0;j<N;j++){bool bget=false;for (int m=0;m<N;m++){for (int n=0;n<N;n++){if (node.node[m][n] == m_nEnd.node[i][j]) {node.iH+=abs(m-i)+abs(n-j);bget=true;break;}}if (bget)break;}}}node.iF =node.iG+node.iH;return node.iH;}bool Chess::NodeEuqal(NODE node1,NODE node2){int sum=0;for (int i=0;i<N;i++)for (int j=0;j<N;j++){if (node1.node[i][j] == node2.node[i][j]) {sum++;}}if (sum==N*N) {return true;}elsereturn false;}bool Chess::InOpen(NODE node,int &index){//查找node是否在Open表中,是的返回true并返回指针位置index OPEN::iterator itOpen=m_vOpen.begin();index=0;for (;itOpen!=m_vOpen.end();itOpen++){if (NodeEuqal(node,*(PNODE)itOpen->node)) {return true;}index++;}return false;}bool Chess::InClose(NODE node,int &index){//查找node是否在InClose表中,是的返回true并返回指针位置index CLOSED::iterator itClosed=m_vClosed.begin();index=0;for (;itClosed!=m_vClosed.end();itClosed++){if (NodeEuqal(node,*(PNODE)itClosed->node)) {return true;}index++;}return false;}bool Chess::NodeExist(NODE node){int i;if (InOpen(node,i) || InClose(node,i)) {return true;}return false;}SUCCERSSOR Chess::ExplortNode(NODE node){//扩展结点,并插入到SUCCERSSOR队列中int i,j;SUCCERSSOR temp;for (i=0;i<N;i++)for (j=0;j<N;j++)if (node.node[i][j]==BLANK){//找到空格,开始扩张,按照空格依次往上下左右扩展,判断其合法性if (j>0) {NODE ntemp=node;ntemp.node[i][j]=ntemp.node[i][j-1];ntemp.node[i][j-1]=BLANK;g_iId++;ntemp.id=g_iId;ntemp.idParent = node.id;ntemp.iG=ntemp.iG+1;CaculateHV(ntemp);temp.push_back(ntemp);}if (j<N-1) {NODE ntemp=node;ntemp.node[i][j]=ntemp.node[i][j+1];ntemp.node[i][j+1]=BLANK;g_iId++;ntemp.id=g_iId;ntemp.idParent = node.id;ntemp.iG=ntemp.iG+1;CaculateHV(ntemp);temp.push_back(ntemp);}if (i>0) {NODE ntemp=node;ntemp.node[i][j]=ntemp.node[i-1][j];ntemp.node[i-1][j]=BLANK;g_iId++;ntemp.id=g_iId;ntemp.idParent = node.id;ntemp.iG=ntemp.iG+1;CaculateHV(ntemp);temp.push_back(ntemp);}if (i<N-1) {NODE ntemp=node;ntemp.node[i][j]=ntemp.node[i+1][j];ntemp.node[i+1][j]=BLANK;g_iId++;ntemp.id=g_iId;ntemp.idParent = node.id;ntemp.iG=ntemp.iG+1;CaculateHV(ntemp);temp.push_back(ntemp);}}return temp;}bool Chess::Algorithms(){NODE nTemp;while (m_vOpen.size()!=0){std::sort(m_vOpen.begin(),m_vOpen.end(),comp);//取出f值最小的进行扩展nTemp = *((PNODE)(m_vOpen.end()-1));m_vOpen.pop_back();m_vClosed.push_back(nTemp);if (NodeEuqal(nTemp,m_nEnd))return true;SUCCERSSOR stemp=ExplortNode(nTemp);SUCCERSSOR::iterator isuc=stemp.begin();for (;isuc!=stemp.end();isuc++){int indexOp,indexCl=0;NODE suc=*(PNODE)isuc,*old;if (InOpen(suc,indexOp)) {old = (PNODE)(m_vOpen.begin()+indexOp);if (suc.iG<old->iG){//若G值比原先的小,则直接修改old结点old->iG = suc.iG;//修改其父节点,指向suc结点old->idParent = suc.idParent;old->iF = old->iG+old->iH;}}else if (InClose(suc,indexCl)){old = (PNODE)(m_vClosed.begin()+indexCl);if (suc.iG<old->iG){//若G值比原先的小,则直接修改old结点old->iG = suc.iG;//修改其父节点,指向suc结点old->idParent = suc.idParent;old->iF = old->iG+old->iH;}}else{m_vOpen.push_back(suc);}}}return false;}/**文件main.cpp,如何使用该类*/#include "Chess.h"#include <IOSTREAM>using namespace std;NODE nStart={{2,8,3,0,1,4,7,6,5},0,0,0,g_iId,0};NODE nEnd={{1,2,3,8,0,4,7,6,5},0,0,0,0,0};int main(int argc,char *argv){Chess *chess=new Chess(nStart,nEnd);if (chess->Algorithms()){cout<<"搜索成功:\n";chess->Show(2);}return 0;}。
用A星算法解决八数码问题
A*算法解决八数码问题1 问题描述1.1什么是八数码问题×八数码游戏包括一个33的棋盘,棋盘上摆放着8个数字的棋子,留下一个空位。
与空位相邻的棋子可以滑动到空位中。
游戏的目的是要达到一个特定的目标状态。
标注的形式化如下:123456781.2问题的搜索形式描述状态:状态描述了8个棋子和空位在棋盘的9个方格上的分布。
初始状态:任何状态都可以被指定为初始状态。
操作符:用来产生4个行动(上下左右移动)。
目标测试:用来检测状态是否能匹配上图的目标布局。
路径费用函数:每一步的费用为1,因此整个路径的费用是路径中的步数。
现在任意给定一个初始状态,要求找到一种搜索策略,用尽可能少的步数得到上图的目标状态。
1.3解决方案介绍1.3.1 算法思想估价函数是搜索特性的一种数学表示,是指从问题树根节点到达目标节点所要耗费的全部代价的一种估算,记为f(n)。
估价函数通常由两部分组成,其数学表达式为f(n)=g(n)+h(n)其中f(n) 是节点n从初始点到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。
保证找到最短路径(最优解)的条件,关键在于估价函数h(n)的选取。
估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。
但能得到最优解。
如果估价值>实际值, 搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
搜索中利用启发式信息,对当前未扩展结点根据设定的估价函数值选取离目标最近的结点进行扩展,从而缩小搜索空间,更快的得到最优解,提高效率。
1.3.2 启发函数进一步考虑当前结点与目标结点的距离信息,令启发函数h ( n )为当前8个数字位与目标结点对应数字位距离和(不考虑中间路径),且对于目标状态有h ( t ) = 0,对于结点m和n (n 是m的子结点)有h ( m ) – h ( n ) <= 1 = Cost ( m, n ) 满足单调限制条件。
用A星算法解决八数码问题
A*算法解决八数码问题1 问题描述什么是八数码问题八数码游戏包括一个3×3的棋盘,棋盘上摆放着8个数字的棋子,留下一个空位。
与空位相邻的棋子可以滑动到空位中。
游戏的目的是要达到一个特定的目标状态。
标注的形式化如下:问题的搜索形式描述状态:状态描述了8个棋子和空位在棋盘的9个方格上的分布。
初始状态:任何状态都可以被指定为初始状态。
操作符:用来产生4个行动(上下左右移动)。
目标测试:用来检测状态是否能匹配上图的目标布局。
路径费用函数:每一步的费用为1,因此整个路径的费用是路径中的步数。
现在任意给定一个初始状态,要求找到一种搜索策略,用尽可能少的步数得到上图的目标状态。
解决方案介绍算法思想(估价函数是搜索特性的一种数学表示,是指从问题树根节点到达目标节点所要耗费的全部代价的一种估算,记为f(n)。
估价函数通常由两部分组成,其数学表达式为f(n)=g(n)+h(n)其中f(n) 是节点n从初始点到目标点的估价函数,g(n) 是在状态空间中从初始节点到n 节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。
保证找到最短路径(最优解)的条件,关键在于估价函数h(n)的选取。
估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。
但能得到最优解。
如果估价值>实际值, 搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
搜索中利用启发式信息,对当前未扩展结点根据设定的估价函数值选取离目标最近的结点进行扩展,从而缩小搜索空间,更快的得到最优解,提高效率。
启发函数进一步考虑当前结点与目标结点的距离信息,令启发函数h ( n )为当前8个数字位与目标结点对应数字位距离和(不考虑中间路径),且对于目标状态有 h ( t ) = 0,对于结点m和n (n 是m的子结点)有h ( m ) – h ( n ) <= 1 = Cost ( m, n ) 满足单调限制条件。
8数码类(a算法实现)
//8数码类class Eight {int e[][] = {{2, 8, 3}, {1, 6, 4}, {7, 0, 5}}; //默认的起始状态int faX, faY; //保存父状态中0的位置int f; //估价函数值Eight former;public Eight() {faX = -1;faY = -1;f = -1;former = null;}public Eight(Eight other) {for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {e[i][j] = other.e[i][j];}}faX = other.faX;faY = other.faY;f = other.f;former = other.former;}public void print() {for (int i1 = 0; i1 < 3; i1++) {for (int j1 = 0; j1 < 3; j1++) {System.out.print(e[i1][j1]);if (j1 == 2) {System.out.println();}}}System.out.println();}public void listAll(Eight e) {while (e.former != null) {e.former.print();e = new Eight(e.former);}return;}}class Queueextends Object { //队列类private int size = 0;Eight qe[] = new Eight[20];public void print() {for (int i = 0; i < size; i++) {qe[i].print();}}public void addElement(Eight e) {qe[size] = e;size++;}public boolean contains(Eight e) {if (size == 0) {return false;}else {for (int i = 0; i < size; i++) {if (qe[i].equals(e)) {return true;}}}return false;}public boolean isEmpty() {if (size == 0) {return true;}else {return false;}}public Eight elementAt(int index) {return qe[index];}public void setElementAt(Eight e, int index) { qe[index] = e;}public int size() {return size;}public int indexOf(Eight e) {for (int i = 0; i < size; i++) {if (qe[i].equals(e)) {return i;}}return -1;}public void removeFirst() {for (int i = 0; i < size; i++) {qe[i] = qe[i + 1];}size--;}public void remove(Eight e) {for (int i = 0; i < size; i++) {if (qe[i].equals(e)) {qe[i] = null;}}size--;}public void removeAllElements() {for (int i = 0; i < size; i++) {qe[i] = null;}size = 0;}}//算法实现类public class Asearch {static int dest[][] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}};static void Swap(Eight ee, int i, int j, int m, int n) { int temp;temp = ee.e[i][j];ee.e[i][j] = ee.e[m][n];ee.e[m][n] = temp;}static int compare(Eight a) {int h = 0, i, j;for (i = 0; i < 3; i++) {for (j = 0; j < 3; j++) {if (a.e[i][j] != dest[i][j]) {h++;}}}return h;}//生成子状态static Queue born(Eight e) {int m = 1, n = 1, i = 0, j = 0;boolean flag = true;Queue sons = new Queue();for (i = 0; i < 3 && flag; i++) {for (j = 0; j < 3 && flag; j++) {if (e.e[i][j] == 0) {flag = false;break;}}}i--;if (i - 1 >= 0) {m = i - 1;if (m != e.faX) {Swap(e, m, j, i, j);//e.print();Eight son1 = new Eight(e);son1.faX = i;son1.faY = j;son1.former = e;sons.addElement(son1);Swap(e, i, j, m, j);}}if (i + 1 < 3) {m = i + 1;if (m != e.faX) {Swap(e, m, j, i, j);//e.print();Eight son2 = new Eight(e);son2.faX = i;son2.faY = j;son2.former = e;sons.addElement(son2);Swap(e, i, j, m, j);}}if (j - 1 >= 0) {n = j - 1;if (n != e.faY) {Swap(e, i, n, i, j);//e.print();Eight son3 = new Eight(e);son3.faX = i;son3.faY = j;son3.former = e;sons.addElement(son3);Swap(e, i, j, i, n);}}if (j + 1 < 3) {n = j + 1;if (n != e.faY) {Swap(e, i, n, i, j);//e.print();Eight son4 = new Eight(e);son4.faX = i;son4.faY = j;son4.former = e;sons.addElement(son4);Swap(e, i, j, i, n);}}return sons;}public static void main(String[] args) {int depth = 0; //深度Eight n = new Eight();Eight temp1 = new Eight(), temp2 = new Eight();//open表Queue open = new Queue();//closed表Queue closed = new Queue();//保存子状态的表Queue son = new Queue();open.addElement(n);while (!open.isEmpty()) {n = open.elementAt(0);open.removeFirst();if (compare(n) == 0) {n.listAll(n);System.out.println("Success!");return;}son = born(n);depth++;int count = son.size();if (count == 0) {continue;}else {for (int t = 0; t < count; t++) {temp1 = son.elementAt(t);if (!open.contains(temp1) && !closed.contains(temp1)) {temp1.f = depth + compare(temp1);open.addElement(temp1);}else if (open.contains(temp1)) {temp1.f = depth + compare(temp1);int pos = open.indexOf(son.elementAt(t));temp2 = open.elementAt(pos);if (temp1.f < temp2.f) {open.setElementAt(temp1, pos);}}else if (closed.contains(temp1)) {temp1.f = depth + compare(temp1);int pos = closed.indexOf(temp1);temp2 = closed.elementAt(pos);if (temp1.f < temp2.f) {closed.remove(son.elementAt(t));open.addElement(temp1);}}} //end for}closed.addElement(n);for (int i = open.size() - 1; i > 0; i--) {for (int j = 0; j < i; j++) {temp1 = (Eight) open.elementAt(j);temp2 = (Eight) open.elementAt(j + 1);if (temp1.f > temp2.f) {Eight tq = new Eight();tq = open.elementAt(j);open.setElementAt(open.elementAt(j + 1), j);open.setElementAt(tq, j + 1);}}}} //end whileSystem.out.println("Fail!");return;} //end main}这个程序是实现人工智能中的A*算法,照着书上的算法做的。
启发式搜索算法解决八数码问题(C语言)
1、程序源代码#include <stdio.h>#include<malloc.h>struct node{int a[3][3];//用二维数组存放8数码int hx;//函数h(x)的值,表示与目标状态的差距struct node *parent;//指向父结点的指针struct node *next;//指向链表中下一个结点的指针};//------------------hx函数-------------------//int hx(int s[3][3]){//函数说明:计算s与目标状态的差距值int i,j;int hx=0;int sg[3][3]={1,2,3,8,0,4,7,6,5};for(i=0;i<3;i++)for(j=0;j<3;j++)if(s[i][j]!=sg[i][j])hx++;return hx;}//-------------hx函数end----------------------////-------------extend扩展函数----------------//struct node *extend(node *ex){ //函数说明:扩展ex指向的结点,并将扩展所得结点组成一条//单链表,head指向该链表首结点,并且作为返回值int i,j,m,n; //循环变量int t; //临时替换变量int flag=0;int x[3][3];//临时存放二维数组struct node *p,*q,*head;head=(node *)malloc(sizeof(node));//headp=head;q=head;head->next=NULL;//初始化for(i=0;i<3;i++)//找到二维数组中0的位置{for(j=0;j<3;j++)if(ex->a[i][j]==0){flag=1;break;}if(flag==1)break;}for(m=0;m<3;m++)//将ex->a赋给xfor(n=0;n<3;n++)x[m][n]=ex->a[m][n];//根据0的位置的不同,对x进行相应的变换//情况1if(i-1>=0){t=x[i][j];x[i][j]=x[i-1][j];x[i-1][j]=t;flag=0;for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}//情况2for(m=0;m<3;m++)//将ex->a重新赋给x,即还原x for(n=0;n<3;n++)x[m][n]=ex->a[m][n];if(i+1<=2){t=x[i][j];x[i][j]=x[i+1][j];x[i+1][j]=t; flag=0;for(m=0;m<3;m++)for(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}//情况3for(m=0;m<3;m++)//将ex->a重新赋给x,即还原x for(n=0;n<3;n++)x[m][n]=ex->a[m][n];if(j-1>=0){t=x[i][j];x[i][j]=x[i][j-1];x[i][j-1]=t;flag=0;for(m=0;m<3;m++)for(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}//情况4for(m=0;m<3;m++)//将ex->a重新赋给x,即还原xfor(n=0;n<3;n++)x[m][n]=ex->a[m][n];if(j+1<=2){t=x[i][j];x[i][j]=x[i][j+1];x[i][j+1]=t;flag=0;for(m=0;m<3;m++)for(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)for(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}head=head->next;return head;}//---------------extend函数end-----------------------////----------------insert函数-------------------------//node* insert(node *open,node * head){ //函数说明:将head链表的结点依次插入到open链表相应的位置, //使open表中的结点按从小到大排序。
八数码C语言A算法详细代码
#include<iostream>#include<>#include<>#include<vector>#include<cmath>using namespace std;struct node{int a[3][3]; [i][j]!=store[0].a[i][j])return false;}}return true;}bool search(int num) ather; [i][j]!=store[num].a[i][j]){test=false;break;}}if(test==false) break;}if(test==true) return false;pre=store[pre].father; ather;(num);while(pre!=0){ ather;}cout<<endl;cout<<"*********数码移动步骤*********"<<endl;int mm=1; [i][j]<<" ";}cout<<endl;}mm++;cout<<endl;}cout<<"所需步数为: "<<store[num].deep<<endl;return;}int get_fn(int num) !=i||store[num].y!=j)&&store[num].a[i][j]==store[0].a[k][l]){ eep;[i][j]==0){store[num].x=i;store[num].y=j;}}}return;}int main(){cout<<"-----------A*算法解决8数码问题------------"<<endl;while(true){(); [i][j]=temp;begin[f++]=temp;}}test=true;for(i=0;i<8;i++){ [i][j]=temp;target[f++]=temp;}}test=true;for(i=0;i<8;i++){ <<endl;cout<<endl;ather=0; one=0;store[1].deep=0; n=get_fn(1);if(check(1)){ n<=store[min].fn&&store[open[i]].gone==0){min=open[i];i_min=i;}}store[min].gone=1;()+i_min); ;n=store[min].y; ather=min; one=0;eep=store[min].deep+1; [m][n]; [m][n]=store[top].a[i][j];store[top].a[i][j]=temp;store[top].x=i; =j;store[top].fn=get_fn(top); cout<<"算法时间为为"<<d<<" ms."<<endl;cout<<endl;}return 0;system("pause"); }。
用A星算法解决八数码问题
A*算法解决八数码问题1 问题描述什么是八数码问题八数码游戏包括一个3×3的棋盘,棋盘上摆放着8个数字的棋子,留下一个空位。
与空位相邻的棋子可以滑动到空位中。
游戏的目的是要达到一个特定的目标状态。
标注的形式化如下:问题的搜索形式描述状态:状态描述了8个棋子和空位在棋盘的9个方格上的分布。
初始状态:任何状态都可以被指定为初始状态。
操作符:用来产生4个行动(上下左右移动)。
目标测试:用来检测状态是否能匹配上图的目标布局。
路径费用函数:每一步的费用为1,因此整个路径的费用是路径中的步数。
现在任意给定一个初始状态,要求找到一种搜索策略,用尽可能少的步数得到上图的目标状态。
解决方案介绍算法思想(估价函数是搜索特性的一种数学表示,是指从问题树根节点到达目标节点所要耗费的全部代价的一种估算,记为f(n)。
估价函数通常由两部分组成,其数学表达式为f(n)=g(n)+h(n)其中f(n) 是节点n从初始点到目标点的估价函数,g(n) 是在状态空间中从初始节点到n 节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。
保证找到最短路径(最优解)的条件,关键在于估价函数h(n)的选取。
估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。
但能得到最优解。
如果估价值>实际值, 搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
搜索中利用启发式信息,对当前未扩展结点根据设定的估价函数值选取离目标最近的结点进行扩展,从而缩小搜索空间,更快的得到最优解,提高效率。
启发函数进一步考虑当前结点与目标结点的距离信息,令启发函数h ( n )为当前8个数字位与目标结点对应数字位距离和(不考虑中间路径),且对于目标状态有 h ( t ) = 0,对于结点m和n (n 是m的子结点)有h ( m ) – h ( n ) <= 1 = Cost ( m, n ) 满足单调限制条件。
实验三:A星算法求解8数码问题实验讲解
实验三:A*算法求解8数码问题实验一、实验目的熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A*算法求解N数码难题,理解求解流程和搜索顺序。
二、实验内容1、八数码问题描述所谓八数码问题起源于一种游戏:在一个3×3的方阵中放入八个数码1、2、3、4、5、6、7、8,其中一个单元格是空的。
将任意摆放的数码盘(城初始状态)逐步摆成某个指定的数码盘的排列(目标状态),如图1所示:图1 八数码问题的某个初始状态和目标状态对于以上问题,我们可以把数码的移动等效城空格的移动。
如图1的初始排列,数码7右移等于空格左移。
那么对于每一个排列,可能的一次数码移动最多只有4中,即空格左移、空格右移、空格上移、空格下移。
最少有两种(当空格位于方阵的4个角时)。
所以,问题就转换成如何从初始状态开始,使空格经过最小的移动次数最后排列成目标状态。
2、八数码问题的求解算法盲目搜索宽度优先搜索算法、深度优先搜索算法启发式搜索启发式搜索算法的基本思想是:定义一个评价函数f,对当前的搜索状态进行评估,找出一个最有希望的节点来扩展。
先定义下面几个函数的含义:f*(n)=g*(n)+h*(n) (1)¥式中g*(n)表示从初始节点s到当前节点n的最短路径的耗散值;h*(n)表示从当前节点n到目标节点g的最短路径的耗散值,f*(n)表示从初始节点s经过n到目标节点g的最短路径的耗散值。
评价函数的形式可定义如(2)式所示:f(n)=g(n)+h(n) (2)其中n是被评价的当前节点。
f(n)、g(n)和h(n)分别表示是对f*(n)、g*(n)和h*(n)3个函数值的估计值。
利用评价函数f(n)=g(n)+h(n)来排列OPEN表节点顺序的图搜索算法称为算法A。
在A算法中,如果对所有的x,h(x)<=h*(x) (3)成立,则称好h(x)为h*(x)的下界,它表示某种偏于保守的估计。
采用h*(x)的下界h(x)为启发函数的A算法,称为A*算法。
八数码问题C语言A星算法详细实验报告含代码
一、实验容和要求八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
例如:(a) 初始状态(b) 目标状态图1 八数码问题示意图请任选一种盲目搜索算法(广度优先搜索或深度优先搜索)或任选一种启发式搜索方法(全局择优搜索,加权状态图搜索,A算法或A* 算法)编程求解八数码问题(初始状态任选)。
选择一个初始状态,画出搜索树,填写相应的OPEN 表和CLOSED表,给出解路径,对实验结果进行分析总结,得出结论。
二、实验目的1. 熟悉人工智能系统中的问题求解过程;2. 熟悉状态空间的盲目搜索和启发式搜索算法的应用;3. 熟悉对八数码问题的建模、求解及编程语言的应用。
三、实验算法A*算法是一种常用的启发式搜索算法。
在A*算法中,一个结点位置的好坏用估价函数来对它进行评估。
A*算法的估价函数可表示为:f'(n) = g'(n) + h'(n)这里,f'(n)是估价函数,g'(n)是起点到终点的最短路径值(也称为最小耗费或最小代价),h'(n)是n到目标的最短路经的启发值。
由于这个f'(n)其实是无法预先知道的,所以实际上使用的是下面的估价函数:f(n) = g(n) + h(n)其中g(n)是从初始结点到节点n的实际代价,h(n)是从结点n到目标结点的最佳路径的估计代价。
在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。
用f(n)作为f'(n)的近似,也就是用g(n)代替g'(n),h(n)代替h'(n)。
这样必须满足两个条件:(1)g(n)>=g'(n)(大多数情况下都是满足的,可以不用考虑),且f必须保持单调递增。
(2)h必须小于等于实际的从当前节点到达目标节点的最小耗费h(n)<=h'(n)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用A*算法实现的八数码问题C++源码
#include <iomanip>
#include <stdlib.h>
#include <iostream.h>
#include <time.h>
int compere=1;
for(int i=0;i<9;i++)
if(num[i]!=num2[i]){
compere=0;
break;
}
if(compere==0) return 0;
#include <stdio.h>
#include <conio.h>
//using namespace std;
//定义默认目标状态
static int target[9]={1,2,3,8,0,4,7,6,5};
//八数码类
class EightNum
{
for(int i=0;i<9;i++)
num[i]=NewEightN.num[i];
diffnum=NewEightN.diffnum;
deapth=NewEightN.deapth+1;
evalfun=diffnum+deapth;
return *this;
}
EightNum& EightNum::operator =(int num2[9]){//"="重载,用于数组赋值
for(int i=0;i<9;i++)
num[i]=num2[i];
return *this;
}
int EightNum::operator ==(EightNum& NewEightN){//"=="重载,用于八数码类中状态的比较
int compere=1;
if(num[i]==0) break;
if(i<3) return 0;
else {
num[i]=num[i-3];
num[i-3]=0;
return 1;
}
}
int movedown(int num[9]){//空格下移
for(int i=0;i<9;i++)
if(num[i]==0) break;
flag=1;
if(num[i]<0||num[i]>8||flag==1){
error++;
}
}
if(error!=0)
cout<<"输入数据错误!请重新输入!"<<endl;
}while(error!=0);
cout<<"是否改变默认的目标状态?(y/n)";
else {
num[i]=num[i+turn 1;
}
}
int exist(int num[9],EightNum *a){//判断是否重复搜索函数
EightNum *t;
for(t=a;t!=NULL;t=t->parent)
if(*t==num) return 1;//调用"=="进行数组比较
else deapth=this->parent->deapth+1;
evalfun=deapth+temp;
}
void EightNum::getnum(int num1[9]){//取出八数码数值
for(int i=0;i<9;i++)
num1[i]=num[i];
}
}
if(error1!=0)
cout<<"输入数据错误!请重新输入!"<<endl;
}while(error1!=0);
}
//实例化初始状态和目标状态,并输出.
EightNum start(num),Target(target);
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<i;j++){
private:
int num[9];
int diffnum;//与目标状态位置不同的数的个数.
int deapth;//派生的深度.
int evalfun;//状态的估价值
public:
EightNum *parent;//生成当前状态的父状态.
EightNum *state_pre;//当前状态前生成状态.
if((num_con==0 && tar_con==0)||(num_con==1 && tar_con==1))
return 1;
else
return 0;
}
//空格移动函数
int moveup(int num[9]){//空格上移
for(int i=0;i<9;i++)
EightNum *state_next;//当前状态后生成状态.
//成员函数声明
EightNum(void);
EightNum(int initnum[9]);
int get_evalfun();
void eval_func();
void getnum(int num1[9]);
void setnum(int num1[9]);
num[i]=i;
}
EightNum::EightNum(int initnum[9]){//用输入的数组初始化num[]
for(int i=0;i<9;i++)
num[i]=initnum[i];
}
int EightNum::get_evalfun(){//返回估价值
return evalfun;
}
void EightNum::eval_func(){//估价函数
int i,temp;
temp=0;
for(i=0;i<9;i++){
if(num[i]!=target[i])
temp++;
}
diffnum=temp;
if(this->parent==NULL) deapth=0;
else {
num[i]=num[i-1];
num[i-1]=0;
return 1;
}
}
int moveright(int num[9]){//空格右移
for(int i=0;i<9;i++)
if(num[i]==0) break;
if(i==2||i==5||i==8) return 0;
if(i>5) return 0;
else {
num[i]=num[i+3];
num[i+3]=0;
return 1;
}
}
int moveleft(int num[9]){//空格左移
for(int i=0;i<9;i++)
if(num[i]==0) break;
if(i==0||i==3||i==6) return 0;
if(num[j]<num[i] && num[j]!=0)
num_con++;
if(target[j]<target[i] && target[j]!=0)
tar_con++;
}
num_con=num_con%2;
tar_con=tar_con%2;
}
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<<num[i]<<" ";
void show(void);