八数码C语言A算法详细代码
用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算法详细代码
#include <iostream> #include<time.h> #include<windows.h> #include<vector> #include<cmath> using namespacestd;struct node{int a[3][3]; int father;int gone;int fn;int x,y; int deep; }; // 存放矩阵// 父节点的位置// 是否遍历过,1为是,0为否// 评价函数的值// 空格的坐标// 节点深度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(nt 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;} return true;}}cout<<endl;cout<<"********* 数码移动步骤 *********" <<endl;int mm=1; // 步数for(int m=temp.size()-1;m>=0;m--){cout<<"---第"vvmmvv "步---:"<<endl; for(int i=0;i<3;i++){ for(intj=0;j<3;j++){ cout<<store[temp[m]].a[i][j]<< " "}cout<<endl;} mm++;cout<<endl;}cout«"所需步数为:"<<store[num].deep<<endl; return;}//返回store[num]的评价函数值 // 评价函数值// 当找到一个值后 ,计算这个值位置与目标位置的距离差后继续寻找下一个值//pre 继续指向store[pre 父节点位置void prin t(i nt n um) {vector<int> temp; int pre=store[num].father;temp.push_back(num);while(pre!=0){ temp.push_back(pre); pre=store[pre].father;//打印路径,store[num 为目标节点// 存放路径 // 从目标节点回溯到初始节点int get_fn(int num) {int fn_temp=0;bool test=true; for(int i=0;i<3;i++){ ,test置 为 falsefor(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;// 清空 store //建立open 表〃store[min]储存fn 值最小的节点 //当前节点在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_tempy/ 用于创建 store[0和store[1],以便下面使用cout«"请输入初始数码棋盘状态,0代表空格:"<<endl; //输入初始状态,储存在store[1]中while(true){ store.clear(); vector<int>open; int i,j,m,n,f;int min; int temp;bool test; top=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)/;/ 获取时间 Count1 double d;store[1].father=0;store[1].gone=0;store[1].deep=0;store[1].fn=get_fn(1);if(check(1)){print(1);//system("pause");//return 0; cout<<endl; continue;} //把初始状态在store 中的位置数压入open 表中// 初始化参数 // 初始节点的父节点为 0// 判断初始状态与目标状态是否相同open.push_back(1); while(!open.empty()){//当open 表不为空时,开始寻找路径if(check(top)) break;min=top;移动为store[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].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);open.push_back(top);if(check(top)){ print(top);//system("pause");//return 0;break;// 移动后的空格坐标// 移动后的fn 值// 把top压入open表中if(search(top)==false){// 检查新增节点是否被访问过,若访问过,则删除此节点top--;store.pop_back(); open.pop_back();}}}}QueryPerformanceCounter(&Count2)/;/ 获取时间Count2 d=(double)(Count2.QuadPart-Count1.QuadPart)/(double)Freg.QuadPart*1000.0/;/ 计算时间差,d 的单位为ms.cout<< "算法时间为为"<<d<< " ms." <<endl;cout<<endl;}return 0; system("pause");}。
用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的大小,从最小路径的节点向下进行。
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值。
八数码问题C语言代码
八数码问题源程序及注释:#include<stdio.h>#include<conio.h>int n,m;typedef struct Node{char matrix[10];/*存储矩阵*/char operate;/*存储不可以进行的操作,L代表不能左移R代表不能右移U代表不能上移D代表不能下移*/char extend;/*是否可以扩展,Y代表可以,N代表不可以*/int father;/*指向产生自身的父结点*/}Node;char start[10]={"83426517 "};/*此处没有必要初始化*/char end[10]={"1238 4765"};/*此处没有必要初始化*/Node base[4000];int result[100];/*存放结果的base数组下标号,逆序存放*/int match()/*判断是否为目标*/{int i;for(i=0;i<9;i++){if(base[n-1].matrix[i]!=end[i]){return 0;}}return 1;}void show()/*显示矩阵的内容*/{int i=1;while(m>=0){int mm=result[m];//clrscr();printf("\n\n\n 状态方格\t\t步骤 %d",i);printf("\n\n\n\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[0],base[mm].mat rix[1],base[mm].matrix[2]);printf("\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[3],base[mm].matrix[4],base[mm].matrix[5]);printf("\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[6],base[mm].matrix[7] ,base[mm].matrix[8]);//sleep(1);m--;i++;}}void leave()/*推理成功后退出程序之前要执行的函数,主要作用是输出结果*/ {n--;while(base[n].father!=-1){result[m]=n;m++;n=base[n].father;}result[m]=0;result[m+1]='\0';show();//clrscr();printf("\n\n\n\n\n\n\n\n\n\t\t\t\t搜索结束\n\n\n\n\n\n\n\n\n\n"); getch();//exit(0);}int left(int x)/*把下标为X的数组中的矩阵的空格左移*/{int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==0||i==3||i==6||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i-1];base[n].matrix[i-1]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='R';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}int right(int x)/*把下标为X的数组中的矩阵的空格右移*/ {int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==2||i==5||i==8||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i+1];base[n].matrix[i+1]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='L';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}int up(int x)/*把下标为X的数组中的矩阵的空格上移*/ {int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==0||i==1||i==2||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i-3];base[n].matrix[i-3]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='D';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}int down(int x)/*把下标为X的数组中的矩阵的空格下移*/ {int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==6||i==7||i==8||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i+3];base[n].matrix[i+3]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='U';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}main(){int i;char a[20],b[20];n=1;//textcolor(LIGHTGREEN);//clrscr();/*以下是输入初始和目标矩阵,并把输入的0转换为空格*/ printf("Please input the start 9 chars:");scanf("%s",a);printf("Please input the end 9 chars:");scanf("%s",b);for(i=0;i<9;i++){if(a[i]=='0'){start[i]=' ';continue;}if(b[i]=='0'){end[i]=' ';continue;}start[i]=a[i];end[i]=b[i];}start[9]='\0';end[9]='\0';for(i=0;i<9;i++){base[0].matrix[i]=start[i];}base[0].operate='N';base[0].extend='Y';base[0].father=-1;/*以上是为第一个base数组元素赋值*/for(i=0;n<4000;i++){if(base[i].extend=='Y'){if(base[i].operate=='L'){right(i);up(i);down(i);}if(base[i].operate=='R'){left(i);up(i);down(i);}if(base[i].operate=='U'){left(i);right(i);down(i);}if(base[i].operate=='D'){left(i);right(i);up(i);}if(base[i].operate=='N'){left(i);right(i);up(i);down(i); }}}}。
8位字节编码中a的编码
8位字节编码中a的编码(最新版)目录1.引言2.8 位字节编码的概述3.a 的 ASCII 编码4.a 的 Unicode 编码5.结论正文【引言】在计算机科学中,字符编码是将字符映射到计算机可以处理的二进制数的过程。
在现代计算机系统中,常用的字符编码包括 ASCII 编码和Unicode 编码。
本文将探讨在 8 位字节编码中,字符"a"的编码方式。
【8 位字节编码的概述】8 位字节编码,顾名思义,是指使用 8 位二进制数来表示一个字符。
在这种编码方式中,任何一个字符都可以用 8 位二进制数来表示,因此,它可以表示 256 种不同的字符。
【a 的 ASCII 编码】在 ASCII 编码中,字符"a"的编码值为 97。
ASCII 编码是一种 7 位编码方式,它可以表示 128 个字符,包括大小写字母、数字和一些特殊字符。
然而,由于 7 位编码只能表示 128 个字符,因此,它不能满足表示所有 Unicode 字符的需求。
【a 的 Unicode 编码】在 Unicode 编码中,字符"a"的编码值为 102。
Unicode 编码是一种16 位编码方式,它可以表示 65536 个字符,包括所有的 Unicode 字符。
在 Unicode 编码中,字符"a"的编码是在 16 位二进制数中的前 8 位,也就是 000000101010。
【结论】在 8 位字节编码中,字符"a"的编码方式取决于所使用的字符编码方案。
在 ASCII 编码中,"a"的编码为 97,而在 Unicode 编码中,"a"的编码为 102。
用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 ) 满足单调限制条件。
八数码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;}。
八数码问题代码及算法分析
八数码 Java代码//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 ;}}//算法实现类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 forclosed.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}class Queue extends 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;}}//八数码.java//package test;import java.io.*;import java.util.Enumeration;import java.util.Hashtable;import java.util.StringTokenizer;/** 八数码的A*算法,* 启发函数为f(x)=g(x)+h(x),g(x)为结点x的深度,h(x)为结点x与目标结点相同元素的个数*/public class 八数码 {结点初始结点;结点目标结点;结点扩展结点[] = new 结点[4]; //保存父结点的四个子结点,顺序存储为上,下,左,右,为扩展的临时数组int f=0;//扩展结点的下标结点 open[] = new 结点[100]; //扩展结点类结点最短路径[] = new 结点[100];//相当与closed表int opennum=0;//open表中结点的个数int closednum =0;//closed表中结点的个数s八数码(int a1[],int a2[]){初始结点 = new 结点(a1);目标结点 = new 结点(a2);//初始结点.不相同结点个数 = 初始结点.不相同结点个数(目标结点);// 目标结点.不相同结点个数 = 目标结点.不相同结点个数(目标结点);// System.out.println("初始结点的不同点的个数:"+初始结点.不相同结点个数);}public class 结点{int 深度,不相同结点个数;int 数码[][] = new int[3][3];boolean 用过吗;public 结点(){用过吗 = false;}public 结点(结点 n){深度 = n.深度;for(int i=0;i<3;i++)for(int j=0;j<3;j++)数码[i][j]=n.数码[i][j];不相同结点个数 = n.不相同结点个数;用过吗 = n.用过吗;}public 结点(int a[]){int m=0;for(int i=0;i<3;i++)for(int j=0;j<3;j++){数码[i][j]=a[m];m=m+1;}用过吗 = false;深度=0;//System.out.println("测试4");//测试}public int[][] 取数值(){return 数码;}public boolean 等于(结点 st)//只是数码不相等 {int[][] s = st.取数值();int i,j;for (i = 0; i < 3; i++)for(j = 0 ; j<3 ;j++)if (s[i][j] != 数码[i][j])return false;return true;}public int[] 零点位置(){int 位置[] = new int[2];for(int i=0;i<3;i++)for(int j=0;j<3;j++)if(this.数码[i][j]==0){位置[0]=i;位置[1]=j;}return 位置;}public int 不相同结点个数(结点 a){int m = 0;for(int i=0 ; i<3 ; i++)for(int j=0; j<3 ;j++){ if( a.数码[i][j] == 数码[i][j] && a.数码[i][j]!=0 ) m=m+1;}return 8-m;}}public static void 打印结点(结点 h){for(int i=0;i<3;i++){for(int j=0;j<3;j++){System.out.print(h.数码[i][j]+" ");}System.out.println();}}public static void 输出结果(Hashtable h){Enumeration enum = h.elements();System.out.println("结果路径是:");while(enum.hasMoreElements()){System.out.println(enum.nextElement()+" ");System.out.println();}}public void 扩展_并查找结点(结点 n){结点 t = new 结点();int temp = 0; //交换数码的中间变量boolean 没找到 = true;while(没找到){if( n == 初始结点){open[opennum]=n; // (状态位置,结点对象) opennum=opennum+1;最短路径[closednum]=n;closednum=closednum+1;}int[] p= n.零点位置();//知道0的位置System.out.println("=================================待扩展的结点;================================");打印结点(n);// if(!n.等于(初始结点))// {// if(存在否(n)){System.out.println("该结点已经在open表中已经存在不用扩展");break;}// }System.out.println("0点位置:"+p[0]+" "+p[1]);if(p[0]==0 && p[1]==0)//如果0点在左上角{//展开(待扩展的结点,扩展方向,0点位置,方向行坐标,方向纵坐标,扩展临时结点数组);//向下扩展if( 展开(n,1,p,1,0,扩展结点) ) {没找到=false; break;}//向右扩展if( 展开(n,3,p,0,1,扩展结点) ) {没找到=false; break;}}else if(p[0] == 0 && p[1] == 1)//如果0点在上中间的话{System.out.println("0点在上中间");//向下扩展if( 展开(n,1,p,1,1,扩展结点) ) {没找到=false; break;}//向左扩展if( 展开(n,2,p,0,0,扩展结点) ) {没找到=false; break;}//向右扩展if( 展开(n,3,p,0,2,扩展结点) ) {没找到=false; break;}}else if(p[0] == 0 && p[1] == 2)//如果0点在右上角{System.out.println("0点在右上角");//向下扩展if( 展开(n,1,p,1,2,扩展结点) ) {没找到=false; break;}//向左扩展if( 展开(n,2,p,0,1,扩展结点) ) {没找到=false; break;}}else if(p[0] == 1 && p[1] == 0)//如果点在左边中间 {System.out.println("0点在左边中间");//向上扩展if( 展开(n,0,p,0,0,扩展结点) ) {没找到=false; break;}//向下扩展if( 展开(n,1,p,2,0,扩展结点) ) {没找到=false; break;}//向右扩展if( 展开(n,3,p,1,1,扩展结点) ) {没找到=false; break;}}else if(p[0] == 1 && p[1] == 1)//如果点在正中间{System.out.println("0点在正中间");//向上扩展if( 展开(n,0,p,0,1,扩展结点) ) {没找到=false; break;}//向下扩展if( 展开(n,1,p,2,1,扩展结点) ) {没找到=false; break;}//向左扩展if( 展开(n,2,p,1,0,扩展结点) ) {没找到=false; break;}//向右扩展if( 展开(n,3,p,1,2,扩展结点) ) {没找到=false; break;}}else if(p[0] == 1 && p[1] == 2)//如果点在右边中间 {System.out.println("0点在右边中间");//向上扩展if( 展开(n,0,p,0,2,扩展结点) ) {没找到=false; break;}//向下扩展if( 展开(n,1,p,2,2,扩展结点) ) {没找到=false; break;}//向左扩展if( 展开(n,2,p,1,1,扩展结点) ) {没找到=false; break;}}else if(p[0] == 2 && p[1] == 0)//如果点在左下角{System.out.println("0点在左下角");//向上扩展if( 展开(n,0,p,1,0,扩展结点) ) {没找到=false; break;}//向右扩展if( 展开(n,3,p,2,1,扩展结点) ) {没找到=false; break;}}else if(p[0] == 2 && p[1] == 1)//如果点在下边中间 {System.out.println("0点在下边中间");//向上扩展if( 展开(n,0,p,1,1,扩展结点) ) {没找到=false; break;}//向左扩展if( 展开(n,2,p,2,0,扩展结点) ) {没找到=false; break;}//向右扩展if( 展开(n,3,p,2,2,扩展结点) ) {没找到=false; break;}}else if(p[0] == 2 && p[1] == 2)//如果点在右下角{System.out.println("0点在右下角");//向上扩展if( 展开(n,0,p,1,2,扩展结点) ) {没找到=false; break;}//向左扩展if( 展开(n,3,p,2,1,扩展结点) ) {没找到=false; break;}}if(没找到){n = 取最优结点();System.out.println("最优结点:");打印结点(n);//测试扩展_并查找结点(n);break;}}}public boolean 存在否(结点 n){for(int i=0;i<opennum;i++){if(open[i].等于(n)) return true;}return false;}public boolean 展开(结点 n,int k,int[] z,int q,int p,结点[] 扩展结点){//展开(待扩展的结点,扩展方向,0点位置,方向行坐标,方向纵坐标,扩展临时结点数组)结点 t = new 结点(n); // 用父结点扩展int flag = 0;int temp;temp = t.数码[z[0]][z[1]];t.数码[z[0]][z[1]] = t.数码[q][p];t.数码[q][p] = temp;String msg="";if(k==0){ msg = new String("向上扩展结果");}else if(k==1){ msg = new String("向下扩展结果");}else if(k==2){ msg = new String("向左扩展结果");}else if(k==3){ msg = new String("向右扩展结果");}System.out.println(msg);打印结点(t);//测试if(!存在否(t))//如果不在open表中(测试此映射表中是否存在与指定值关联的键){t.深度 = n.深度+1;t.不相同结点个数 = t.不相同结点个数(目标结点);if(t.等于(目标结点)){System.out.println("=======恭喜!终于找到目标结点了^-^!!!=======");打印结点(t);//测试最短路径[closednum]=t;closednum = closednum+1;return true;}else {扩展结点[f] = t;//如果在open表中不存在则装入扩展结点数组中f=f+1;}System.out.println("该结点的深度:"+t.深度+"\n该结点的不同与目标结点的个数:"+t.不相同结点个数);int r = t.深度+t.不相同结点个数;System.out.println("择优权值:"+r);System.out.println();}else{System.out.println("该结点已经分析过了");return false;}return false;}public 结点取最优结点(){结点最优;System.out.println("扩展数组的长度:"+有值的个数(扩展结点));最优 = 扩展结点[0];for(int i=0;i<有值的个数(扩展结点);i++){if((扩展结点[i].深度+扩展结点[i].不相同结点个数)<(最优.深度+最优.不相同结点个数)){最优 = 扩展结点[i];}}for(int i =0;i<有值的个数(扩展结点);i++){if(扩展结点[i]==最优) continue;open[opennum]=扩展结点[i];opennum=opennum+1;}//从open表中取出最优结点,放入closed表中最短路径[closednum]=最优;closednum = closednum+1;f=0;//重置扩展数组下标return 最优;}public static int[] 读数(){int[] a = new int[9];int i=0;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));try{while(a.length<=9 && i<=8){StringTokenizer st = new StringTokenizer(br.readLine());while(st.hasMoreTokens()){if(i > 8) break;a[i]=Integer.parseInt(st.nextToken());i=i+1;}}}catch(Exception e){}return a;}public static int 有值的个数(结点 m[]){int n =0;for(int i=0;i<m.length;i++){if(m[i] != null) n=n+1;if(m[i] == null) break;}return n;}public static void main(String args[]){int a1[] =new int[9];int a2[] ={1,2,3,8,0,4,7,6,5};System.out.println("请输入初始结点:"); a1 = 八数码.读数();//System.out.println("请输入目标结点:"); //a2 = 八数码.读数();八数码 bsm = new 八数码(a1,a2);bsm.扩展_并查找结点(bsm.初始结点);System.out.println("应用程序终止");}}。
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数码问题程序源代码
#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 * Solution_Astar(struct node *p);void Expand_n(struct node *p);struct node * Search_A(struct node *name,struct node *temp);void Print_result(struct node *p);/* 定义8数码的节点状态*/typedef struct node{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={{3,8,2,1,0,5,7,6,4},1,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; //用于记录扩展节点总数int main(void){struct node s,*target;Copy_node(&s_0,&s);Calculate_f(0,&s); //拷贝8数码初始状态,初始化代价值target=Solution_Astar(&s); //求解主程序if(target) Print_result(target); //输出解路径else printf("问题求解失败!");getch();return 0;}/******************************************//* A*算法*//******************************************/struct node * Solution_Astar(struct node *p){struct node *n,*temp;Add_to_open(p); //将s_0放入open表while(open!=NULL) //只要open表中还有元素,就继续对代价最小的节点进行扩展{n=open; //n指向open表中当前要扩展的元素temp=open->next;Add_to_closed(n);open=temp;if(Test_A_B(n,&s_g)) //当前n指向节点为目标时,跳出程序结束;否则,继续下面的步骤return n;Expand_n(n); //扩展节点n}return NULL;}/*******************************************************//* 生成当前节点n通过走步可以得到的所有状态*//*******************************************************/void Expand_n(struct node *p){struct node *temp,*same;if(p->j_0>=1) //空格所在列号不小于1,可左移{temp=p->father;if(temp!=NULL&&temp->i_0==p->i_0&&temp->j_0-1==p->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(p,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=p; //新节点指向其父节点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(p->j_0<=1) //空格所在列号不大于1,可右移{temp=p->father;if(temp!=NULL&&temp->i_0==p->i_0&&temp->j_0+1==p->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(p,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=p; //新节点指向其父节点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(p->i_0>=1) //空格所在列号不小于1,上移{temp=p->father;if(temp!=NULL&&temp->i_0==p->i_0-1&&temp->j_0==p->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(p,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=p; //新节点指向其父节点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(p->i_0<=1) //空格所在列号不大于1,下移{temp=p->father;if(temp!=NULL&&temp->i_0==p->i_0+1&&temp->j_0==p->j_0) //新节点与其祖父节点相同;else //新节点与其祖父节点不同,或其父节点为起始节点{temp=(struct node *)malloc(sizeof(struct node)); //给新节点分配空间Copy_node(p,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=p; //新节点指向其父节点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下移}/*******************************************************//* 添加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;}/**********************************************************//* 判断两个节点A、B状态是否相同,相同则返回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;}}/******************************************//* 计算某个节点状态的代价值*//******************************************/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++){switch(p->s[i][j]){case 0: temp+=abs(i-1)+abs(j-1); break;case 1: temp+=abs(i-0)+abs(j-0); break;case 2: temp+=abs(i-0)+abs(j-1); break;case 3: temp+=abs(i-0)+abs(j-2); break;case 4: temp+=abs(i-1)+abs(j-2); break;case 5: temp+=abs(i-2)+abs(j-2); break;case 6: temp+=abs(i-2)+abs(j-1); break;case 7: temp+=abs(i-2)+abs(j-0); break;case 8: temp+=abs(i-1)+abs(j-0); break;}}}p->h=temp;p->f=deepth+p->h;}/********************************************//* 将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"); 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("当前:f=%d,d=%d,h=%d\n",temp->f,temp->d,temp->h);printf("当前节点状态为:\n");for(i=0;i<=2;i++){for(j=0;j<=2;j++){printf("%d ",temp->s[i][j]);}printf("\n");}printf("\n");}}。
八数码问题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)。
#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");}。