八数码C语言A算法详细代码
数码问题C语言A星算法详细实验报告含代码
一、实验内容和要求八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
例如:图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)。
八数码问题代码及算法分析
八数码 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("应用程序终止");}}。
八数码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");}。
八数码问题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返回。
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星算法解决八数码问题
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*算法求解8数码难题,理解求解流程和搜索顺序。
二、实验原理A*算法是一种启发式图搜索算法,其特点在于对估价函数的定义上。
对于一般的启发式图搜索,总是选择估价函数f值最小的节点作为扩展节点。
因此,f 是根据需要找到一条最小代价路径的观点来估算节点的,所以,可考虑每个节点n的估价函数值为两个分量:从起始节点到节点n的实际代价g(n)以及从节点n 到达目标节点的估价代价h(n),且h(n)<=h*(n),h*(n)为n节点到目标节点的最优路径的代价。
八数码问题是在3×3的九宫格棋盘上,排放有8个刻有1~8数码的将牌。
棋盘中有一个空格,允许紧邻空格的某一将牌可以移到空格中,这样通过平移将牌可以将某一将牌布局变换为另一布局。
针对给定的一种初始布局或结构(目标状态),问如何移动将牌,实现从初始状态到目标状态的转变。
如图1所示表示了一个具体的八数码问题求解。
图1 八数码问题的求解三、实验内容1、参考A*算法核心代码,以8数码问题为例实现A*算法的求解程序(编程语言不限),要求设计两种不同的估价函数。
2、在求解8数码问题的A*算法程序中,设置相同的初始状态和目标状态,针对不同的估价函数,求得问题的解,并比较它们对搜索算法性能的影响,包括扩展节点数、生成节点数等。
3、对于8数码问题,设置与图1所示相同的初始状态和目标状态,用宽度优先搜索算法(即令估计代价h(n)=0的A*算法)求得问题的解,记录搜索过程中的扩展节点数、生成节点数。
4、提交实验报告和源程序。
四.实验截图五.源代码#include<iostream>#include"stdio.h"#include"stdlib.h"#include"time.h"#include"string.h"#include<queue>#include<stack>using namespace std;const int N=3;//3*3棋?盘ìconst int Max_Step=32;//最?大洙?搜?索÷深?度èenum Direction{None,Up,Down,Left,Right};//方?向ò,?分?别纄对?应畖上?下?左哩?右?struct Chess//棋?盘ì{int chessNum[N][N];//棋?盘ì数簓码?int Value;//评à估à值μDirection BelockDirec;//所ù屏á蔽?方?向òstruct Chess * Parent;//父?节ú点?};void PrintChess(struct Chess *TheChess);//打洙?印?棋?盘ìstruct Chess * MoveChess(struct Chess * TheChess,Direction Direct,bool CreateNewChess);//移?动ˉ棋?盘ì数簓字?int Appraisal(struct Chess * TheChess,struct Chess * Target);//估à价?函ˉ数簓struct Chess * Search(struct Chess* Begin,struct Chess * Target);//A*搜?索÷函ˉ数簓int main(){//本?程ì序ò的?一?组哩?测a试?数簓据Y为a/*初?始?棋?盘ì*1 4 0**3 5 2**6 7 8**//*目?标括?棋?盘ì*0 1 2**3 4 5**6 7 8**/Chess Target;Chess *Begin,*ChessList;Begin=new Chess;int i;cout<<"请?输?入?初?始?棋?盘ì,?各÷数簓字?用?空?格?隔?开a:阰"<<endl;for(i=0;i<N;i++){for(int j=0;j<N;j++){cin>>Begin->chessNum[i][j];}}cout<<"请?输?入?目?标括?棋?盘ì,?各÷数簓字?用?空?格?隔?开a:阰"<<endl;for(i=0;i<N;i++){for(int j=0;j<N;j++){cin>>Target.chessNum[i][j];}}//获?取?初?始?棋?盘ìAppraisal(Begin,&Target);Begin->Parent=NULL;Begin->BelockDirec=None;Target.Value=0;cout<<"初?始?棋?盘ì:";PrintChess(Begin);cout<<"目?标括?棋?盘ì:";PrintChess(&Target);ChessList=Search(Begin,&Target);//搜?索÷//打洙?印?if(ChessList){/*将?返う?回?的?棋?盘ì列表括?利?用?栈?将?其?倒?叙e*/Chess *p=ChessList;stack<Chess *>Stack;while(p->Parent!=NULL){Stack.push(p);p=p->Parent;}cout<<"搜?索÷结á果?:"<<endl;int num=1;while(!Stack.empty()){cout<<"第台?<<num<<"步?: ";num++;PrintChess(Stack.top());Stack.pop();}cout<<"\n完?成é!"<<endl;}elsecout<<"搜?索÷不?到?结á果?,?搜?索÷深?度è大洙?于?2\n"<<endl;return 0;}//打洙?印?棋?盘ìvoid PrintChess(struct Chess *TheChess){cout<<"(评à估à值μ为a";cout<<TheChess->Value;cout<<")"<<endl;for(int i=0;i<N;i++){cout<<" ";for(int j=0;j<N;j++){cout<<TheChess->chessNum[i][j]<<" ";}cout<<endl;}}//移?动ˉ棋?盘ìstruct Chess * MoveChess(struct Chess * TheChess,Direction Direct,bool CreateNewChess) {struct Chess * NewChess;//获?取?空?闲D格?位?置?int i,j;for(i=0;i<N;i++){bool HasGetBlankCell=false;for(j=0;j<N;j++){if(TheChess->chessNum[i][j]==0){HasGetBlankCell=true;break;}}if(HasGetBlankCell)break;}int ii=i,jj=j;bool AbleMove=true;//判D断?是?否?可é以?移?动ˉswitch(Direct){case Up:i++;if(i>=N)AbleMove=false;break;case Down:i--;if(i<0)AbleMove=false;break;case Left:j++;if(j>=N)AbleMove=false;break;case Right:j--;if(j<0)AbleMove=false;break;};if(!AbleMove)//不?可é以?移?动ˉ则ò返う?回?原-节ú点?{return TheChess;}if(CreateNewChess){NewChess=new Chess();for(int x=0;x<N;x++){for(int y=0;y<N;y++)NewChess->chessNum[x][y]=TheChess->chessNum[x][y];//创洹?建¨新?棋?盘ì,?此?时骸?值μ与?原-棋?盘ì一?致?}}elseNewChess=TheChess;NewChess->chessNum[ii][jj] = NewChess->chessNum[i][j];//移?动ˉ数簓字?NewChess->chessNum[i][j]=0;//将?原-数簓字?位?置?设Θ?置?为a空?格?return NewChess;}//估à价?函ˉ数簓int Appraisal(struct Chess * TheChess,struct Chess * Target){int Value=0;for(int i=0;i<N;i++){for(int j=0;j<N;j++){if(TheChess->chessNum[i][j]!=Target->chessNum[i][j])Value++;}}TheChess->Value=Value;return Value;}//A*搜?索÷函ˉ数簓struct Chess * Search(struct Chess* Begin,struct Chess * Target){Chess *p1,*p2,*p;int Step=0;//深?度èp=NULL;queue<struct Chess *> Queue;Queue.push(Begin);//初?始?棋?盘ì入?队ó//搜?索÷do{p1=(struct Chess *)Queue.front();Queue.pop();//出?队ófor(int i=1;i<=4;i++)//分?别纄从洙?四?个?方?向ò推?导?出?新?子哩?节ú点? {Direction Direct=(Direction)i;if(Direct==p1->BelockDirec)//跳?过y屏á蔽?方?向òcontinue;p2=MoveChess(p1,Direct,true);//移?动ˉ数簓码?if(p2!=p1)//数簓码?是?否?可é以?移?动ˉ{Appraisal(p2,Target);//对?新?节ú点?估à价?if(p2->Value<=p1->Value)//是?否?为a优?越?节ú点?{p2->Parent=p1;switch(Direct)//设Θ?置?屏á蔽?方?向ò,防え?止1往?回?推?{case Up:p2->BelockDirec=Down;break;case Down:p2->BelockDirec=Up;break;case Left:p2->BelockDirec=Right;break;case Right:p2->BelockDirec=Left;break;}Queue.push(p2);//存?储洹?节ú点?到?待鋣处鋦理え?队ó列if(p2->Value==0)//为a0则ò,搜?索÷完?成é{p=p2;i=5;}}else{delete p2;//为a劣ⅷ?质ê节ú点?则ò抛×弃úp2=NULL;}}}Step++;if(Step>Max_Step)return NULL;}while(p==NULL || Queue.size()<=0);return p;}六、实验报告要求1、分析不同的估价函数对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 ) 满足单调限制条件。
启发式搜索算法解决八数码问题(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星算法的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)。
8位字节编码中a的编码
8位字节编码中a的编码
(原创版)
目录
1.8 位字节编码的概述
2.字母"a"的 ASCII 编码
3.字母"a"的 Unicode 编码
4.字母"a"的 UTF-8 编码
正文
【1.8 位字节编码的概述】
8 位字节编码是一种将字符编码成字节的方式,每个字符需要一个或多个字节来表示。
这种方式广泛应用于计算机系统中,以便存储和传输各种字符。
【2.字母"a"的 ASCII 编码】
在 ASCII 编码中,字母"a"的编码值为 97。
ASCII 编码是一种将字符编码成字节的方式,每个字符都对应一个唯一的编码值,因此字母"a"的 ASCII 编码就是 97。
【3.字母"a"的 Unicode 编码】
在 Unicode 编码中,字母"a"的编码值为 103。
Unicode 编码是一种将字符编码成字节的方式,每个字符都对应一个唯一的编码值,因此字母"a"的 Unicode 编码就是 103。
【4.字母"a"的 UTF-8 编码】
在 UTF-8 编码中,字母"a"的编码值为 61。
UTF-8 编码是一种将字符编码成字节的方式,每个字符都对应一个唯一的编码值,因此字母"a"的 UTF-8 编码就是 61。
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。
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*算法,照着书上的算法做的。
用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";}。
A星算法求解八数码问题
2.1盲目搜索
宽度优先搜索算法、深度优先搜索算法
2.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,
图1八数码问题的某个初始状态和目标状态
对于以上问题,我们可以把数码的移动等效城空格的移动。如图1的初始排列,数码7右移等于空格左移。那么对于每一个排列,可能的一次数码移动最多只有4中,即空格左移、空格右移、空格上移、空格下移。最少有两种(当空格位于方阵的4个角时)。所以,问题就转换成如何从初始状态开始,使空格经过最小的移动次数最后排列成目标状态。
所以要把所有的不在位的将牌移动到各自的目标位置上至少要移动从他们各自的位置到目标位置的距离和这么多次所以最有路径的耗散值不会比该值小因此该启发函数hn满足a算法的条件
A*算法求解八数码问题
1、八数码问题描述
所谓八数码问题起源于一种游戏:在一个3×3的方阵中放入八个数码1、2、3、4、5、6、7、8,其中一个单元格是空的。将任意摆放的数码盘(城初始状态)逐步摆成某个指定的数码盘的排列(目标状态),如图1所示
八数码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");}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include<iostream>
#include<time.h>
#include<windows.h>
#include<vector>
#include<cmath>
usingnamespace 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])
returnfalse;
}
}
returntrue;
}
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) returnfalse;
pre=store[pre].father; //pre继续指向store[pre]父节点位置}
returntrue;
}
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(); //清空store
vector<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;。