C语言实现8数码问题

合集下载

八数码问题范例程序

八数码问题范例程序

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>using namespace std;int mat[10][10];const int dx[] = {-1,1,0,0};const int dy[] = {0,0,1,-1};const char dir[] = {'u','d','r','l'};typedef int state[9];const int maxstate = 1e6;int vis[maxstate];int fact[9];char in[30];int cnt = 1;struct node {state st;int x,y,z;int h,g;int hash;node(){memset(st,0,sizeof(st));}bool operator < (const node &other)const{return h != other.h ? h > other.h : g>other.g; }} goal,start;int get_h(node &a){int pos1[30],pos2[30];for(int i = 0; i < 9; ++i) {if(a.st[i] != -1) pos1[a.st[i]] = i;if(goal.st[i] != -1) pos2[goal.st[i]] = i; }int sum = 0;for(int i = 0; i < 8; ++i) {sum += mat[pos1[i]][pos2[i]];}return sum;}int get_hash(node &a){int code = 0;for(int i = 0; i < 9; ++i) {int cnt = 0;for(int j = i + 1; j < 9; ++j) if(a.st[j] < a.st[i]) cnt++;code += fact[8-i]*cnt;}return code;}struct father {state fst;int pre;char op;} fa[maxstate];void init_search_table(){fact[0] = 1;for(int i = 1; i < 9; ++i) fact[i] = fact[i-1] * i;}void astar(){ //鎼滅储priority_queue<node>que;que.push(start);while(!que.empty()){node u = que.top();que.pop();for(int i = 0; i < 4; ++i){node v = u;v.x += dx[i];v.y += dy[i];if(v.x >= 0 && v.x < 3 && v.y >= 0&&v.y < 3){swap(v.st[3*v.x + v.y],v.st[u.x*3 + u.y]); //灏嗙┖浣嶅拰鐩搁偦浣嶄氦鎹? v.hash = get_hash(v); //寰楀埌HASH鍊? if(vis[v.hash] == 0){ //鍒ゆ柇鏄 惁宸查亶鍘嗕笖鏄 惁鍙 锛屽悗鑰呭彲浠ヤ笉瑕? vis[v.hash] = 1; //淇濆瓨鏂瑰悜v.g++; //宸茶姳浠d环+1memcpy(fa[v.hash].fst,u.st,sizeof(u.st));fa[v.hash].pre=u.hash;fa[v.hash].op = dir[i]; //淇濆瓨璺 緞v.h = get_h(v); //寰楀埌鏂扮殑浼颁环鍑芥暟H que.push(v); //鍏ラ槦}if(v.hash == goal.hash)return ;}}}}void putway(int a){if(a == start.hash) return ;putway(fa[a].pre);printf("State %d:--->\n ",cnt++);for(int i = 0; i < 9; ++i){if(fa[a].fst[i] == -1) printf("x ");else printf("%d ",fa[a].fst[i] + 1);if((i) % 3 == 2) {printf("\n");printf(" ");}}printf("%c\n",fa[a].op);}void input(){int len = strlen(in);int z = 0;for(int i = 0; i < 9; ++i) goal.st[i] = i;goal.st[8] = -1;for(int i = 0; i < len; ++i) {if(in[i] >= '0'&&in[i] <='9'||in[i] =='x') {if(in[i] == 'x') {start.st[z] = -1;int x = z/3,y = z%3;start.x = x,start.y = y,start.z = z;}else start.st[z] = in[i] - '0' - 1;z++;}}start.hash = get_hash(start);start.h = get_h(start);start.g = 0;goal.hash = get_hash(goal);goal.x = 8/3;goal.y = 8%3;goal.z = 8;}void init_mat(){for(int i = 0; i < 9; ++i) {for(int j = 0; j < 9; ++j) {if(i != j) {int x1 = i/3,y1 = i%3;int x2 = j/3,y2 = j%3;mat[i][j] = abs(x1 - x2) + abs(y1 - y2);}}}}bool isok(){int sum = 0;for(int i = 0; i < 9; ++i) {for(int j = i + 1; j < 9; ++j) {if(start.st[j] >= 0&&start.st[i]>=0&&start.st[i] > start.st[j])sum++;}}return !(sum&1);}int main(){//freopen("in","r",stdin);memset(vis,0,sizeof(vis));init_search_table();init_mat();while(gets(in) != NULL){memset(vis,0,sizeof(vis));input();if(!isok()) puts("unsolvable");else {astar();cnt = 1;putway(goal.hash);printf("State %d:--->\n ",cnt++); for(int i = 0; i < 9; ++i){if(goal.st[i] == -1) printf("x "); else printf("%d ",goal.st[i] + 1); if((i) % 3 == 2) {printf("\n");printf(" ");}}printf("\n");}}}。

C语言实现8数码问题

C语言实现8数码问题

1、实验目的(1)熟悉人工智能系统中的问题求解过程;(2)熟悉状态空间中的盲目搜索策略;(3)掌握盲目搜索算法,重点是宽度优先搜索和深度优先搜索算法。

2、实验要求用VC语言编程,采用宽度优先搜索和深度优先搜索方法,求解8数码问题3、实验内容(1)采用宽度优先算法,运行程序,要求输入初始状态假设给定如下初始状态S02 8 31 6 47 0 5和目标状态Sg2 1 64 0 87 5 3验证程序的输出结果,写出心得体会。

(2)对代码进行修改(选作),实现深度优先搜索求解该问题提示:每次选扩展节点时,从数组的最后一个生成的节点开始找,找一个没有被扩展的节点。

这样也需要对节点添加一个是否被扩展过的标志。

4 源代码及实验结果截图#include<stdio.h>#include<stdlib.h>#include<math.h>//八数码状态对应的节点结构体struct Node{int s[3][3];//保存八数码状态,0代表空格int f,g;//启发函数中的f和g值struct Node * next;struct Node *previous;//保存其父节点};int open_N=0; //记录Open列表中节点数目//八数码初始状态int inital_s[3][3]={2,8,3,1,6,4,7,0,5};//八数码目标状态int final_s[3][3]={2,1,6,4,0,8,7,5,3};//------------------------------------------------------------------------//添加节点函数入口,方法:通过插入排序向指定表添加//------------------------------------------------------------------------void Add_Node( struct Node *head, struct Node *p){struct Node *q;if(head->next)//考虑链表为空{ q = head->next;if(p->f < head->next->f){//考虑插入的节点值比链表的第一个节点值小p->next = head->next;head->next = p;}else {while(q->next)//考虑插入节点x,形如a<= x <=b{if((q->f < p->f ||q->f == p->f) && (q->next->f > p->f || q->next->f == p->f)){ p->next = q->next;q->next = p;break;}q = q->next;}if(q->next == NULL) //考虑插入的节点值比链表最后一个元素的值更大q->next = p;}else head->next = p;}//------------------------------------------------------------------------//删除节点函数入口//------------------------------------------------------------------------void del_Node(struct Node * head, struct Node *p ){struct Node *q;q = head;while(q->next){if(q->next == p){q->next = p->next;p->next = NULL;if(q->next == NULL) return;// free(p);}q = q->next;}}//------------------------------------------------------------------------//判断两个数组是否相等函数入口//------------------------------------------------------------------------int equal(int s1[3][3], int s2[3][3])int i,j,flag=0;for(i=0; i< 3 ; i++)for(j=0; j< 3 ;j++)if(s1[i][j] != s2[i][j]){flag = 1; break;}if(!flag)return 1;else return 0;}//------------------------------------------------------------------------//判断后继节点是否存在于Open或Closed表中函数入口//------------------------------------------------------------------------int exit_Node(struct Node * head,int s[3][3], struct Node *Old_Node) {struct Node *q=head->next;int flag = 0;while(q)if(equal(q->s,s)) {flag=1;Old_Node->next = q;return 1;}else q = q->next;if(!flag) return 0;}//------------------------------------------------------------------------//计算p(n)的函数入口//其中p(n)为放错位的数码与其正确的位置之间距离之和//具体方法:放错位的数码与其正确的位置对应下标差的绝对值之和//------------------------------------------------------------------------int wrong_sum(int s[3][3]){int i,j,fi,fj,sum=0;for(i=0 ; i<3; i++)for(j=0; j<3; j++){for(fi=0; fi<3; fi++)for(fj=0; fj<3; fj++)if((final_s[fi][fj] == s[i][j])){sum += fabs(i - fi) + fabs(j - fj);break;}}return sum;}//------------------------------------------------------------------------//获取后继结点函数入口//检查空格每种移动的合法性,如果合法则移动空格得到后继结点//------------------------------------------------------------------------int get_successor(struct Node * BESTNODE, int direction, struct Node *Successor)//扩展BESTNODE,产生其后继结点SUCCESSOR {int i,j,i_0,j_0,temp;for(i=0; i<3; i++)for(j=0; j<3; j++)Successor->s[i][j] = BESTNODE->s[i][j];//获取空格所在位置for(i=0; i<3; i++)for(j=0; j<3; j++)if(BESTNODE->s[i][j] == 0){i_0 = i; j_0 = j;break;} switch(direction){case 0: if((i_0-1)>-1 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0-1][j_0];Successor->s[i_0-1][j_0] = temp;return 1;}else return 0;case 1: if((j_0-1)>-1){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0-1];Successor->s[i_0][j_0-1] = temp;return 1;}else return 0;case 2: if( (j_0+1)<3){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0+1];Successor->s[i_0][j_0+1] = temp;return 1;}else return 0;case 3: if((i_0+1)<3 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0+1][j_0];Successor->s[i_0+1][j_0] = temp;return 1;}else return 0;}}//------------------------------------------------------------------------//从OPen表获取最佳节点函数入口//------------------------------------------------------------------------struct Node * get_BESTNODE(struct Node *Open){return Open->next;}//------------------------------------------------------------------------//输出最佳路径函数入口//------------------------------------------------------------------------void print_Path(struct Node * head){struct Node *q, *q1,*p;int i,j,count=1;p = (struct Node *)malloc(sizeof(struct Node));//通过头插法变更节点输出次序p->previous = NULL;q = head;while(q){q1 = q->previous;q->previous = p->previous;p->previous = q;q = q1;}q = p->previous;while(q){if(q == p->previous)printf("八数码的初始状态:\n");else if(q->previous == NULL)printf("八数码的目标状态:\n");else printf("八数码的中间态%d\n",count++);for(i=0; i<3; i++)for(j=0; j<3; j++){printf("%4d",q->s[i][j]);if(j == 2)printf("\n");}printf("f=%d, g=%d\n\n",q->f,q->g);q = q->previous;}}//------------------------------------------------------------------------//A*子算法入口:处理后继结点//------------------------------------------------------------------------void sub_A_algorithm(struct Node * Open, struct Node * BESTNODE, struct Node * Closed,struct Node *Successor){struct Node * Old_Node = (struct Node *)malloc(sizeof(struct Node));Successor->previous = BESTNODE;//建立从successor返回BESTNODE的指针Successor->g = BESTNODE->g + 1;//计算后继结点的g值//检查后继结点是否已存在于Open和Closed表中,如果存在:该节点记为old_Node,比较后继结点的g值和表中old_Node节点//g值,前者小代表新的路径比老路径更好,将Old_Node的父节点改为BESTNODE,并修改其f,g值,后者小则什么也不做。

八数码为题求解

八数码为题求解

#include <stdio.h>#include <string.h>#include <math.h>#include <malloc.h>#include <stdlib.h>typedef struct node{int array[3][3];//int g;//搜索的深度int h;//不在位的数字到达目标状态的距离之和int f;//启发函数中的f值node *fwd;//node *bwd;};int step=0;int start_s[3][3]={//起始状态2,1,6,4,0,8,7,5,3};int target_s[3][3]={//目标状态1,2,3,8,0,4,7,6,5};int open_n=0;//open表中的元素个数int get_h(int array[3][3]);//得到启发函数的值node *move_up(node *org_node);//空格上移node *move_down(node *org_node);//空格下移node *move_left(node *org_node);//空格左移node *move_right(node *org_node);//空格右移int equal_s(int s1[3][3],int s2[3][3]);//判断两个状态是否相同void copy_s(int s1[3][3],int s2[3][3]);//将第二个数组的内容复制到第一个数组int new_state(node *head,node *s1);//判断所得节点是不是新节点void insert_open(node *head,node *p);//在open表中插入节点,链表是h+g值升序排列的链表void inser_close(node *head,node *p);//在close表中插入节点,并且采用头插入法void del_open(node *head);//从open表中删除头节点void display(int s[3][3]);//展示状态void displayl(node *p);//按照最优路径输出各个节点int get_h(int array[3][3]){int sum=0;int i,j,m,n;for(i=0;i<3;i++)for (j=0;j<3;j++){for(m=0;m<3;m++)for (n=0;n<3;n++){if(array[i][j]==target_s[m][n]){sum=sum+(int)fabs(i-m)+(int)fabs(j-n);break;}}}return sum;}/*int get_h(int array[3][3]){int sum=0;for (int i=0;i<3;i++)for(int j=0;j<3;j++)if(array[i][j]!=target_s[i][j])sum++;return sum;}*/node *move_up(node *org_node){int i,j;node *new_n=new node;copy_s(new_n->array,org_node->array);for(i=0;i<3;i++){for(j=0;j<3;j++){if(new_n->array[i][j]==0){if(i==0)return NULL;else{new_n->array[i][j]=new_n->array[i-1][j];new_n->array[i-1][j]=0;new_n->g=org_node->g+1;new_n->h=get_h(new_n->array);new_n->f=new_n->g+new_n->h;new_n->bwd=org_node;new_n->fwd=NULL;return new_n;}}}}return NULL;}node *move_down(node *org_node){int i,j;node *new_n=new node;copy_s(new_n->array,org_node->array);for(i=0;i<3;i++){for(j=0;j<3;j++){if(new_n->array[i][j]==0){if(i==2)return NULL;else{new_n->array[i][j]=new_n->array[i+1][j];new_n->array[i+1][j]=0;new_n->g=org_node->g+1;new_n->h=get_h(new_n->array);new_n->f=new_n->g+new_n->h;new_n->bwd=org_node;new_n->fwd=NULL;return new_n;}}}}return NULL;}node *move_left(node *org_node){int i,j;node *new_n=new node;copy_s(new_n->array,org_node->array);for(i=0;i<3;i++){for(j=0;j<3;j++){if(new_n->array[i][j]==0){if(j==0)return NULL;else{new_n->array[i][j]=new_n->array[i][j-1];new_n->array[i][j-1]=0;new_n->g=org_node->g+1;new_n->h=get_h(new_n->array);new_n->f=new_n->g+new_n->h;new_n->bwd=org_node;new_n->fwd=NULL;return new_n;}}}}return NULL;}node *move_right(node *org_node){int i,j;node *new_n=new node;copy_s(new_n->array,org_node->array);for(i=0;i<3;i++){for(j=0;j<3;j++){if(new_n->array[i][j]==0){if(j==2)return NULL;else{new_n->array[i][j]=new_n->array[i][j+1];new_n->array[i][j+1]=0;new_n->g=org_node->g+1;new_n->h=get_h(new_n->array);new_n->f=new_n->g+new_n->h;new_n->bwd=org_node;new_n->fwd=NULL;return new_n;}}}}return NULL;}int equal_s(int s1[3][3],int s2[3][3]){int i,j;for (i=0;i<3;i++)for (j=0;j<3;j++){if(s1[i][j]!=s2[i][j])return 0;}return 1;}void copy_s(int s1[3][3],int s2[3][3]){int i,j;for(i=0;i<3;i++)for (j=0;j<3;j++){s1[i][j]=s2[i][j];}}int new_state(node *head1,node *head2,node *s1) {node *q;q=head1->fwd;while(q!=NULL){if(equal_s(s1->array,q->array))return 0;q=q->fwd;}q=head2->fwd;while(q!=NULL){if(equal_s(s1->array,q->array))return 0;q=q->fwd;}return 1;}void insert_open(node *head,node *p){node *q;if(head->fwd){q=head->fwd;if (p->f<head->fwd->f){p->fwd=head->fwd;head->fwd=p;}else{while (q->fwd){if ((q->f < p->f ||q->f == p->f) && (q->fwd->f > p->f )){p->fwd=q->fwd;q->fwd=p;break;}q=q->fwd;}if (q->fwd==NULL){q->fwd=p;p->fwd=NULL;}}}else{head->fwd=p;p->fwd=NULL;}}void inser_close(node *head,node *p){p->fwd=head->fwd;head->fwd=p;}void del_open(node *head,node *p){node *q;q=head;while (q->fwd){if(q->fwd==p){q->fwd=p->fwd;free(p);break;}q=q->fwd;}}void display(int s[3][3]){int i=0;int j=0;printf("------step%d-----------\n",step++);for(i;i<3;i++){for(j=0;j<3;j++)printf("%d\t",s[i][j]);printf("\n");}}void displayl(node *p){node *q=new node;q->fwd=NULL;while(p){p->fwd=q->fwd;q->fwd=p;p=p->bwd;}while(q->fwd){display(q->fwd->array);q=q->fwd;}delete q;}void main(void){node *head1=new node;node *head2=new node;node *p;head1->fwd=NULL;head1->bwd=NULL;head2->fwd=NULL;head2->bwd=NULL;node *first=new node;copy_s(first->array,start_s);first->fwd=NULL;first->bwd=NULL;first->g=0;first->h=get_h(first->array);first->f=first->g+first->h;insert_open(head1,first);open_n++;while (open_n>0){node *temp=new node;node *temp1;copy_s(temp->array,head1->fwd->array);temp->g=head1->fwd->g;temp->h=head1->fwd->h;temp->f=head1->fwd->f;temp->bwd=head1->fwd->bwd;temp->fwd=head1->fwd->fwd;inser_close(head2,temp);// display(head2->fwd->array);if(equal_s(temp->array,target_s)){displayl(temp);display(target_s);exit(EXIT_SUCCESS);}temp1=head1->fwd;temp=move_up(temp1);if(temp&&new_state(head1,head2,temp)){insert_open(head1,temp);open_n++;}temp=move_down(temp1);if(temp&&new_state(head1,head2,temp)){insert_open(head1,temp);open_n++;}temp=move_left(temp1);if(temp&&new_state(head1,head2,temp)){insert_open(head1,temp);open_n++;}temp=move_right(temp1);if(temp&&new_state(head1,head2,temp)){insert_open(head1,temp);open_n++;}p=head1->fwd;while(p){//若删除节点恰好是head1中某些元素的父节点,则将这些元素的父节点指针指向head2的第一个节点(其父节点的复制节点)if(p->bwd==temp1)p->bwd=head2->fwd;p=p->fwd;}del_open(head1,temp1);open_n--;}}。

8数码问题分析及程序代码

8数码问题分析及程序代码

八数码问题1、问题描述所谓八数码问题是指:将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放在一块3×3的数码盘上。

放牌时要求不能重叠。

于是,在3×3的数码盘上出现了一个空格。

现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,将任意摆放的数码盘逐步摆成某种特殊的排列。

2、问题分析首先,八数码问题包括一个初始状态(strat) 和 目标状态(goal),所谓解八数码问题就是在两个状态间寻找一系列可过渡状态(strat-> strat 1-> strat 2->...->goal )。

这个状态是否存在表示空格)图13、 数据结构 定义结构体Node 如下: typedef struct{int num[9];char cur_expension; //记录是否可以扩展,Y 代表可以扩展,N 代表不可以。

char Operate; //表示不可以执行的操作,'L'代表不能左移,'R'代表不能右移, //'U'代表不能上移,'D'代表不能下移,'C'代表可以任意移动。

int father; //记录父节点的下标。

}Node;Node state[MAXSIZE]; //将搜索过的状态存储于该数组中。

4、广度优先搜索广度优先搜索是指按节点的层次进行搜索,本层的节点没有搜索完毕时,不能对下层节点进行处理,即深度越小的节点越先得到扩展,也就是说先产生的节点先得以扩展处理,直至找到目标为止。

求解八数码问题的搜索过程:如图2所示,把所有可能的算符应用到开始节点(即空格上移、空格左移、空格右移、空格下移),图2只是演示了两个扩展结点,如此继续下去,直到发现目标节点。

图2 变量定义及函数说明:1 2 3 45 6 7 8 01 2 37 4 5 8 0 61 2 34 5 67 8 0#define SUM 100//限定只搜索前50步,50步以后如果仍然没有搜索到结果,认为无解。

八数码问题:C++广度搜索实现

八数码问题:C++广度搜索实现

⼋数码问题:C++⼴度搜索实现毕竟新⼿上路23333,有谬误还请指正。

课程设计遇到⼋数码问题(这也是⼀坨),也查过⼀些资料并不喜欢⽤类函数写感觉这样规模⼩些的问题没有必要,⼀开始⽤深度搜索却发现深搜会陷⼊⽆底洞,如果设定了深度限制⼜会有很多情况⽆法找到,然后果断放弃,改⽤⼴度搜索。

如果要改善代码效率还可以⽤双向搜索,即从起始状态和最终状态同时搜索,找到相同状态,这样搜索时间会缩短⼀半。

此外还可以⽤A*(启发式算法)会显得⾼端很多。

题⽬要求:在⼀个3*3的棋盘上,随机放置1到8的数字棋⼦,剩下⼀个空位。

数字可以移动到空位(编程时,空位可⽤0代替,且可以理解为是空位的上、下、左、右移动),经过若⼲次移动后,棋局到达指定⽬标状态。

数组表⽰棋局状态。

⽤函数表⽰空格(0)的移动,使⽤函数具有前提条件,满⾜条件才可以使⽤。

⽤⼴度优先或深度优先搜索求解。

还可以使⽤启发式求解,以提⾼搜索效率。

要求:①编程求解问题;②给出中间状态;③给出解序列(函数调⽤序列)1 #include <iostream>2 #include <vector>3 #include <string>4 #include <queue>5 #include <algorithm>6 #include <cmath>7 #include <ctime>8 #include <cstdio>9 #include <sstream>10 #include <deque>11 #include <functional>12 #include <iterator>13 #include <list>14 #include <map>15 #include <memory>16 #include <stack>17 #include <set>18 #include <numeric>19 #include <utility>20 #include <cstring>21 #include <fstream>2223using namespace std;24int board[25]; //初始状态,⼀维数组模拟⼆维25int destboard[25]; //⽬标状态26int dx[] = {-1, 0, 1, 0}; //数字0的移动偏移量27int dy[] = {0, 1, 0, -1};28 map<int, bool> mark; //记录已搜索的状态2930int lists(int i, int j)31 {32return i*5 + j; //返回i, j⼆维数组的⼀维位置33 }3435int judge() //运算前判断是否可以找到⼀种对于初末状态可⾏的变换36 {37int first_d[10],last_d[10],i,j=6,k,rank1=0,rank2=0;38for(i=1;i<=9;i++) //初状态赋值给first_d[10]39 {40while(1)41 {42if(j==9){j=11;}43if(j==14){j=16;}44 first_d[i]=destboard[j];45 j++;46break;47 }48 }49 j=1;i=1;50for(k=1;k<=9;k++) //最终状态赋值给last_d[10]51 {52while(1)53 {54 last_d[k]=board[lists(i, j)];55 j++;56if(j==4){i++;j=1;}57break;58 }59 }6061for(j=2;j<=9;j++) //计算初状态的奇偶性62 {63for(i=1;i<j;i++)64 {65if(first_d[i]>first_d[j]&&first_d[i]!=0&&first_d[j]!=0){rank1++;}66 }67 }6869for(j=2;j<=9;j++) //计算末状态的奇偶性70 {71for(i=1;i<j;i++)72 {73if(last_d[i]>last_d[j]&&last_d[i]!=0&&last_d[j]!=0){rank2++;}74 }75 }76int a1=rank1%2,a2=rank2%2;77if(a1!=a2){return0;} //判断奇偶性是否相同,相同才可以从出状态变到末状态 78else{return1;}79 }8081struct Stat //结构体三个参数82 {83int step; // 步数84int board[25]; // 状态85 Stat(int *b, int s=0)86 {87 memcpy(this->board, b, sizeof(int)*25); //对状态的赋值操作88 step = s;89 }90 };9192bool ok(int *b) // 判断是否到已经达⽬标状态93 {94for(int i=1; i<=3; ++i)95for(int j=1; j<=3; ++j)96 {97if(b[lists(i, j)] != destboard[lists(i, j)])98return false;99 }100return true;101 }102103int Bfs()104 {105int judge_first=judge();106 ofstream ofs; //建⽴数据外存⽂件107 ofs.open("output.dat");108if(judge_first==0){cout<<"不存在"<<endl;return2333333;}109if(judge_first==1)110 {111 queue<Stat> que; //建队que112 que.push(Stat(board, 0)); // 初始状态⼊队113while(que.size())114 {115int m=0, mk=1; // 记录状态m,以及基数mk116 Stat p = que.front(); //取出队头元素117for(int i=1; i<=3; ++i)118 {119for(int j=1; j<=3; ++j)120 {121 ofs<<p.board[lists(i, j)]<<"";122 }123 ofs<<endl;124 }125 ofs<<endl;126127 que.pop(); //出队128129if(ok(p.board))130 {131return p.step; // 到达⽬标则返回最短步数132 }133134for(int i=1; i<=3; ++i) // 这个是为了标记初始状态,不能遗漏135for(int j=1; j<=3; ++j)136 {137 m+=p.board[lists(i, j)]*mk;138 mk*=10;139 }140if(!mark.count(m)) // 未标记则标记141 mark[m] = true;142143for(int k=0; k<4; ++k) // 四个⽅向搜索144 {145 Stat n(p.board, p.step+1); // n是下⼀步搜索的状态146int zx, zy; // zx,zy存放当前状态0的位置147148for(int i=1; i<=3; ++i) // 搜索当前状态的0的位置149for(int j=1; j<=3; ++j)150 {151if(p.board[lists(i,j)]==0)152 {153 zx = i;154 zy = j;155break;156 }157if(p.board[lists(i,j)]==0)158break;159 }160161int nx = zx+dx[k]; //下⼀个状态的0的位置162int ny = zy+dy[k];163 m = 0; //标记状态164 mk = 1;165 swap(n.board[lists(nx,ny)],n.board[lists(zx, zy)]); //交换166167for(int i=1; i<=3; ++i)168for(int j=1; j<=3; ++j)169 {170 m+=n.board[lists(i, j)]*mk;171 mk*=10;172 }173if(!mark.count(m))174 {175 mark[m] = true;176 que.push(n); //若未搜索过,则⼊队177 }178 }179 }180 ofs.close(); //结束外存181return2333333;182 }183return0;184 }185186int main()187 {188 cout<<"⼴度搜索⼋数码问题:\n";189 cout<<"请输⼊初始状态⽤0-8表⽰\n";190 memset(board, 0, sizeof(board));191for(int i=1; i<=3; ++i)192for(int j=1; j<=3; ++j)193 scanf("%1d", &board[lists(i, j)]);194195 cout<<"请输⼊结束状态\n";196for(int m=6;m<=8;m++){scanf("%d",&destboard[m]);}197for(int m=11;m<=13;m++){scanf("%d",&destboard[m]);}198for(int m=16;m<=18;m++){scanf("%d",&destboard[m]);}199 mark.clear();200201 cout<<"准备搜索...\n";202 system("pause");203 cout<<"搜索中.....\n";204205int t=Bfs();206 cout<<"搜索完毕,过程已经以⽂件的形式存储\n";207if(t==2333333){cout<<"没有找到"<<endl;}208else{cout<<"深度为:"<<t<< endl;}209 system("pause");210return0;211 }输⼊初始状态和最终状态,中间过程会⽣成在”output.dat”中。

C语言实现8数码问题

C语言实现8数码问题

C语言实现8数码问题1、实验目的(1)熟悉人工智能系统中的问题求解过程;(2)熟悉状态空间中的盲目搜索策略;(3)掌握盲目搜索算法,重点是宽度优先搜索和深度优先搜索算法。

2、实验要求用VC语言编程,采用宽度优先搜索和深度优先搜索方法,求解8数码问题3、实验内容(1)采用宽度优先算法,运行程序,要求输入初始状态假设给定如下初始状态S02 8 31 6 47 0 5和目标状态Sg2 1 64 0 87 5 3验证程序的输出结果,写出心得体会。

(2)对代码进行修改(选作),实现深度优先搜索求解该问题提示:每次选扩展节点时,从数组的最后一个生成的节点开始找,找一个没有被扩展的节点。

这样也需要对节点添加一个是否被扩展过的标志。

4 源代码及实验结果截图#include#include#include//八数码状态对应的节点结构体struct Node{int s[3][3];//保存八数码状态,0代表空格int f,g;//启发函数中的f和g值struct Node * next;struct Node *previous;//保存其父节点};int open_N=0; //记录Open列表中节点数目//八数码初始状态int inital_s[3][3]={2,8,3,1,6,4,7,0,5};//八数码目标状态int final_s[3][3]={2,1,6,4,0,8,7,5,3};//------------------------------------------------------------------------//添加节点函数入口,方法:通过插入排序向指定表添加//------------------------------------------------------------------------void Add_Node( struct Node *head, struct Node *p){struct Node *q;if(head->next)//考虑链表为空{ q = head->next;if(p->f < head->next->f){//考虑插入的节点值比链表的第一个节点值小p->next = head->next;head->next = p;}else {while(q->next)//考虑插入节点x,形如a<= x <=bif((q->f < p->f ||q->f == p->f) && (q->next->f > p->f || q->next->f == p->f)){ p->next = q->next;q->next = p;break;}q = q->next;}if(q->next == NULL) //考虑插入的节点值比链表最后一个元素的值更大q->next = p;}else head->next = p;}//------------------------------------------------------------------------//删除节点函数入口//------------------------------------------------------------------------void del_Node(struct Node * head, struct Node *p ) {struct Node *q;q = head;while(q->next){if(q->next == p){q->next = p->next;p->next = NULL;if(q->next == NULL) return;// free(p);}q = q->next;}//------------------------------------------------------------------------//判断两个数组是否相等函数入口//------------------------------------------------------------------------int equal(int s1[3][3], int s2[3][3])int i,j,flag=0;for(i=0; i< 3 ; i++)for(j=0; j< 3 ;j++)if(s1[i][j] != s2[i][j]){flag = 1; break;}if(!flag)return 1;else return 0;}//------------------------------------------------------------------------//判断后继节点是否存在于Open或Closed表中函数入口//------------------------------------------------------------------------int exit_Node(struct Node * head,int s[3][3], struct Node *Old_Node) {struct Node *q=head->next;int flag = 0;while(q)if(equal(q->s,s)) {flag=1;Old_Node->next = q;return 1;}else q = q->next;if(!flag) return 0;//------------------------------------------------------------------------//计算p(n)的函数入口//其中p(n)为放错位的数码与其正确的位置之间距离之和//具体方法:放错位的数码与其正确的位置对应下标差的绝对值之和//------------------------------------------------------------------------int wrong_sum(int s[3][3]){int i,j,fi,fj,sum=0;for(i=0 ; i<3; i++)for(j=0; j<3; j++){for(fi=0; fi<3; fi++)for(fj=0; fj<3; fj++)if((final_s[fi][fj] == s[i][j])){sum += fabs(i - fi) + fabs(j - fj);break;}}return sum;}//------------------------------------------------------------------------//获取后继结点函数入口//检查空格每种移动的合法性,如果合法则移动空格得到后继结点//------------------------------------------------------------------------int get_successor(struct Node * BESTNODE, int direction, struct Node *Successor)//扩展BESTNODE,产生其后继结点SUCCESSOR {int i,j,i_0,j_0,temp;for(i=0; i<3; i++)for(j=0; j<3; j++)Successor->s[i][j] = BESTNODE->s[i][j];//获取空格所在位置for(i=0; i<3; i++)for(j=0; j<3; j++)if(BESTNODE->s[i][j] == 0){i_0 = i; j_0 = j;break;} switch(direction){case 0: if((i_0-1)>-1 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0-1][j_0];Successor->s[i_0-1][j_0] = temp;return 1;}else return 0;case 1: if((j_0-1)>-1){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0-1];Successor->s[i_0][j_0-1] = temp;return 1;}else return 0;case 2: if( (j_0+1)<3){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0+1];Successor->s[i_0][j_0+1] = temp;return 1;}else return 0;case 3: if((i_0+1)<3 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0+1][j_0];Successor->s[i_0+1][j_0] = temp;return 1;}else return 0;}}//------------------------------------------------------------------------//从OPen表获取最佳节点函数入口//------------------------------------------------------------------------struct Node * get_BESTNODE(struct Node *Open){return Open->next;}//------------------------------------------------------------------------//输出最佳路径函数入口//------------------------------------------------------------------------void print_Path(struct Node * head){struct Node *q, *q1,*p;int i,j,count=1;p = (struct Node *)malloc(sizeof(struct Node));//通过头插法变更节点输出次序p->previous = NULL;q = head;while(q){q1 = q->previous;q->previous = p->previous;p->previous = q;q = q1;}q = p->previous;while(q){if(q == p->previous)printf("八数码的初始状态:\n");else if(q->previous == NULL)printf("八数码的目标状态:\n"); else printf("八数码的中间态%d\n",count++);for(i=0; i<3; i++)for(j=0; j<3; j++){printf("%4d",q->s[i][j]);if(j == 2)printf("\n");}printf("f=%d, g=%d\n\n",q->f,q->g);q = q->previous;}}//------------------------------------------------------------------------//A*子算法入口:处理后继结点//------------------------------------------------------------------------void sub_A_algorithm(struct Node * Open, struct Node * BESTNODE, struct Node * Closed,struct Node *Successor) {struct Node * Old_Node = (struct Node *)malloc(sizeof(struct Node));Successor->previous = BESTNODE;//建立从successor返回BESTNODE的指针Successor->g = BESTNODE->g + 1;//计算后继结点的g值//检查后继结点是否已存在于Open和Closed表中,如果存在:该节点记为old_Node,比较后继结点的g值和表中old_Node节点//g值,前者小代表新的路径比老路径更好,将Old_Node的父节点改为BESTNODE,并修改其f,g值,后者小则什么也不做。

八数码C语言A算法详细代码

八数码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代码

八数码问题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返回。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1、实验目的(1)熟悉人工智能系统中的问题求解过程;(2)熟悉状态空间中的盲目搜索策略;(3)掌握盲目搜索算法,重点是宽度优先搜索和深度优先搜索算法。

2、实验要求用VC语言编程,采用宽度优先搜索和深度优先搜索方法,求解8数码问题3、实验内容(1)采用宽度优先算法,运行程序,要求输入初始状态假设给定如下初始状态S02 8 31 6 47 0 5和目标状态Sg2 1 64 0 87 5 3验证程序的输出结果,写出心得体会。

(2)对代码进行修改(选作),实现深度优先搜索求解该问题提示:每次选扩展节点时,从数组的最后一个生成的节点开始找,找一个没有被扩展的节点。

这样也需要对节点添加一个是否被扩展过的标志。

4 源代码及实验结果截图#include<stdio.h>#include<stdlib.h>#include<math.h>//八数码状态对应的节点结构体struct Node{int s[3][3];//保存八数码状态,0代表空格int f,g;//启发函数中的f和g值struct Node * next;struct Node *previous;//保存其父节点};int open_N=0; //记录Open列表中节点数目//八数码初始状态int inital_s[3][3]={2,8,3,1,6,4,7,0,5};//八数码目标状态int final_s[3][3]={2,1,6,4,0,8,7,5,3};//------------------------------------------------------------------------ //添加节点函数入口,方法:通过插入排序向指定表添加//------------------------------------------------------------------------ void Add_Node( struct Node *head, struct Node *p){struct Node *q;if(head->next)//考虑链表为空{ q = head->next;if(p->f < head->next->f){//考虑插入的节点值比链表的第一个节点值小p->next = head->next;head->next = p;}else {while(q->next)//考虑插入节点x,形如a<= x <=b{if((q->f < p->f ||q->f == p->f) && (q->next->f > p->f || q->next->f == p->f)){p->next = q->next;q->next = p;break;}q = q->next;}if(q->next == NULL) //考虑插入的节点值比链表最后一个元素的值更大q->next = p;}}else head->next = p;}//------------------------------------------------------------------------//删除节点函数入口//------------------------------------------------------------------------void del_Node(struct Node * head, struct Node *p )struct Node *q;q = head;while(q->next){if(q->next == p){q->next = p->next;p->next = NULL;if(q->next == NULL) return;// free(p);}q = q->next;}}//------------------------------------------------------------------------ //判断两个数组是否相等函数入口//------------------------------------------------------------------------ int equal(int s1[3][3], int s2[3][3]){int i,j,flag=0;for(i=0; i< 3 ; i++)for(j=0; j< 3 ;j++)if(s1[i][j] != s2[i][j]){flag = 1; break;}if(!flag)return 1;else return 0;//------------------------------------------------------------------------ //判断后继节点是否存在于Open或Closed表中函数入口//------------------------------------------------------------------------ int exit_Node(struct Node * head,int s[3][3], struct Node *Old_Node){struct Node *q=head->next;int flag = 0;while(q)if(equal(q->s,s)) {flag=1;Old_Node->next = q;return 1;}else q = q->next;if(!flag) return 0;}//------------------------------------------------------------------------ //计算p(n)的函数入口//其中p(n)为放错位的数码与其正确的位置之间距离之和//具体方法:放错位的数码与其正确的位置对应下标差的绝对值之和//------------------------------------------------------------------------ int wrong_sum(int s[3][3]){int i,j,fi,fj,sum=0;for(i=0 ; i<3; i++)for(j=0; j<3; j++){for(fi=0; fi<3; fi++)for(fj=0; fj<3; fj++)if((final_s[fi][fj] == s[i][j])){sum += fabs(i - fi) + fabs(j - fj);break;}}return sum;}//------------------------------------------------------------------------//获取后继结点函数入口//检查空格每种移动的合法性,如果合法则移动空格得到后继结点//------------------------------------------------------------------------int get_successor(struct Node * BESTNODE, int direction, struct Node *Successor)//扩展BESTNODE,产生其后继结点SUCCESSOR{int i,j,i_0,j_0,temp;for(i=0; i<3; i++)for(j=0; j<3; j++)Successor->s[i][j] = BESTNODE->s[i][j];//获取空格所在位置for(i=0; i<3; i++)for(j=0; j<3; j++)if(BESTNODE->s[i][j] == 0){i_0 = i; j_0 = j;break;}switch(direction){case 0: if((i_0-1)>-1 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0-1][j_0];Successor->s[i_0-1][j_0] = temp;return 1;}else return 0;case 1: if((j_0-1)>-1){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0-1];Successor->s[i_0][j_0-1] = temp;return 1;}else return 0;case 2: if( (j_0+1)<3){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0+1];Successor->s[i_0][j_0+1] = temp;return 1;}else return 0;case 3: if((i_0+1)<3 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0+1][j_0];Successor->s[i_0+1][j_0] = temp;return 1;}else return 0;}}//------------------------------------------------------------------------ //从OPen表获取最佳节点函数入口//------------------------------------------------------------------------ struct Node * get_BESTNODE(struct Node *Open){return Open->next;}//------------------------------------------------------------------------ //输出最佳路径函数入口//------------------------------------------------------------------------ void print_Path(struct Node * head){struct Node *q, *q1,*p;int i,j,count=1;p = (struct Node *)malloc(sizeof(struct Node));//通过头插法变更节点输出次序p->previous = NULL;q = head;while(q){q1 = q->previous;q->previous = p->previous;p->previous = q;q = q1;}q = p->previous;while(q){if(q == p->previous)printf("八数码的初始状态:\n");else if(q->previous == NULL)printf("八数码的目标状态:\n"); else printf("八数码的中间态%d\n",count++);for(i=0; i<3; i++)for(j=0; j<3; j++){printf("%4d",q->s[i][j]);if(j == 2)printf("\n");}printf("f=%d, g=%d\n\n",q->f,q->g);q = q->previous;}}//------------------------------------------------------------------------//A*子算法入口:处理后继结点//------------------------------------------------------------------------void sub_A_algorithm(struct Node * Open, struct Node * BESTNODE, struct Node * Closed,struct Node *Successor) {struct Node * Old_Node = (struct Node *)malloc(sizeof(struct Node));Successor->previous = BESTNODE;//建立从successor返回BESTNODE的指针Successor->g = BESTNODE->g + 1;//计算后继结点的g值//检查后继结点是否已存在于Open和Closed表中,如果存在:该节点记为old_Node,比较后继结点的g值和表中old_Node 节点//g值,前者小代表新的路径比老路径更好,将Old_Node的父节点改为BESTNODE,并修改其f,g值,后者小则什么也不做。

相关文档
最新文档