人工智能实验报告-八数码 (1)

时间:2024.4.9

《人工智能》实验一题目

实验一  启发式搜索算法

1. 实验内容

使用启发式搜索算法求解8数码问题。

⑴ 编制程序实现求解8数码问题算法,采用估价函数

其中:是搜索树中结点的深度;为结点的数据库中错放的棋子个数;为结点的数据库中每个棋子与其目标位置之间的距离总和。

⑵ 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是的上界的的定义,并测试使用该估价函数是否使算法失去可采纳性。

2. 实验目的

熟练掌握启发式搜索算法及其可采纳性。

3.数据结构与算法设计

该搜索为一个搜索树。为了简化问题,搜索树节点设计如下:

typedef struct Node//棋盘

{//节点结构体

    int data[9];

    double f,g;

    struct Node * parent; //父节点

}Node,*Lnode;

int data[9];    数码数组:记录棋局数码摆放状态。

struct Chess * Parent;  父节点:指向父亲节点。

下一步可以通过启发搜索算法构造搜索树。

1、局部搜索树样例:

2、搜索过程

  搜索采用广度搜索方式,利用待处理队列辅助,逐层搜索(跳过劣质节点)。搜索过程如下:

  (1)、把原棋盘压入队列;

  (2)、从棋盘取出一个节点;

  (3)、判断棋盘估价值,为零则表示搜索完成,退出搜索;

  (4)、扩展子节点,即从上下左右四个方向移动棋盘,生成相应子棋盘;

(5)、对子节点作评估,是否为优越节点(子节点估价值小于或等于父节点则为优越节点),是则把子棋盘压入队列,否则抛弃;

  (5)、跳到步骤(2);

3、算法的评价

完全能解决简单的八数码问题,但对于复杂的八数码问题还是无能为力。现存在的一些优缺点。

1、可以改变数码规模(N),来扩展成N*N的棋盘,即扩展为N数码问题的求解过程。

<!--[if !supportLists]-->2、  <!--[endif]-->内存泄漏。由于采用倒链表的搜索树结构,简化了数据结构,但有部分被抛弃节点的内存没有很好的处理,所以会造成内存泄漏;

<!--[if !supportLists]-->3、  <!--[endif]-->采用了屏蔽方向,有效防止往回搜索(节点的回推),但没能有效防止循环搜索,所以不能应用于复杂度较大的八数码问题;


源码:
#include <stdlib.h>

#include <stdio.h>

#include <math.h>

typedef struct Node

{//节点结构体

    int data[9];

       double f,g;

       struct Node * parent;

}Node,*Lnode;

typedef struct Stack

{//OPEN CLOSED 表结构体

       Node * npoint;

       struct Stack * next;

}Stack,* Lstack;

Node * Minf(Lstack * Open)

{//选取OPEN表上f值最小的节点,返回该节点地址

       Lstack temp = (*Open)->next,min = (*Open)->next,minp = (*Open);

       Node * minx;

    while(temp->next != NULL)

       {

              if((temp->next ->npoint->f) < (min->npoint->f))

              {

                     min = temp->next;

                     minp = temp;

              }

              temp = temp->next;

       }

       minx = min->npoint;

       temp = minp->next;

       minp->next = minp->next->next;

       free(temp);

       return minx;

}

int Canslove(Node * suc, Node * goal)

{//判断是否可解

       int a = 0,b = 0,i,j;

       for(i = 1; i< 9;i++)

              for(j = 0;j < i;j++)

              {

                     if((suc->data[i] > suc->data[j]) && suc->data[j] != 0)a++;

                     if((goal->data[i] > goal->data[j]) && goal->data[j] != 0)b++;

              }

       if(a%2 == b%2)return 1;

       else return 0;

}

int Equal(Node * suc,Node * goal)

{//判断节点是否相等,相等,不相等

       for(int i = 0; i < 9; i ++ )

              if(suc->data[i] != goal->data[i])return 0;

    return 1;

}

Node * Belong(Node * suc,Lstack * list)

{//判断节点是否属于OPEN表或CLOSED表,是则返回节点地址,否则返回空地址

       Lstack temp = (*list) -> next ;

       if(temp == NULL)return NULL;

       while(temp != NULL)

       {

              if(Equal(suc,temp->npoint))return temp -> npoint;

              temp = temp->next;

       }

       return NULL;

}

void Putinto(Node * suc,Lstack * list)

{//把节点放入OPEN 或CLOSED 表中

    Stack * temp;

       temp =(Stack *) malloc(sizeof(Stack));

       temp->npoint = suc;

       temp->next = (*list)->next;

       (*list)->next = temp;

}

///////////////计算f值部分-开始//////////////////////////////

double Fvalue(Node suc, Node goal, int m)

{//计算f值

       switch(m)

       {

       case 1:{

                     int error(Node,Node);

                     int w=0;

                     w=error(suc,goal);

                     return w+suc.g;

                    

                 }

       case 2:{

                     double Distance(Node,Node,int);

                     double p = 0;

                     for(int i = 1; i <= 8; i++)

                            p = p + Distance(suc, goal, i);

                     return p + suc.g; //f = h + g;

                    

                 }

       default:

              break;

       }

                                           

}

int error(Node suc,Node goal)

{//计算错位个数

       int w,i;

       w=0;

       for(i=0;i<9;i++){

              if(suc.data[i]!=goal.data[i])

                     w++;

       }

       return w;

}

double Distance(Node suc, Node goal, int i)

{//计算方格的错位距离

       int k,h1,h2;

       for(k = 0; k < 9; k++)

       {

              if(suc.data[k] == i)h1 = k;

              if(goal.data[k] == i)h2 = k;

       }

       return double(fabs(h1/3 - h2/3) + fabs(h1%3 - h2%3));

}

///////////////计算f值部分-结束//////////////////////////////

///////////////////////扩展后继节点部分的函数-开始/////////////////

int BelongProgram(Lnode * suc ,Lstack * Open ,Lstack * Closed ,Node goal ,int m)

{//判断子节点是否属于OPEN或CLOSED表并作出相应的处理

       Node * temp = NULL;

       int flag = 0;

       if((Belong(*suc,Open) != NULL) || (Belong(*suc,Closed) != NULL))

       {

              if(Belong(*suc,Open) != NULL) temp = Belong(*suc,Open);

              else temp = Belong(*suc,Closed);

              if(((*suc)->g) < (temp->g))

              {

                     temp->parent = (*suc)->parent;

                     temp->g = (*suc)->g;

                     temp->f = (*suc)->f;

                  flag = 1;

              }

       }

       else

       {

              Putinto(* suc, Open);

              (*suc)->f = Fvalue(**suc, goal, m);

       }

       return flag;

}

int Canspread(Node suc, int n)

{//判断空格可否向该方向移动,,,表示空格向上向下向左向右移

       int i,flag = 0;

       for(i = 0;i < 9;i++)

              if(suc.data[i] == 0)break;

       switch(n)

       {

       case 1:

              if(i/3 != 0)flag = 1;break;

       case 2:

              if(i/3 != 2)flag = 1;break;

       case 3:

              if(i%3 != 0)flag = 1;break;

       case 4:

              if(i%3 != 2)flag = 1;break;

       default:break;

       }

       return flag ;

}

void Spreadchild(Node * child,int n)

{//扩展child节点的字节点n表示方向,,,表示空格向上向下向左向右移

       int i,loc,temp;

       for(i = 0;i < 9;i++)

              child->data[i] = child->parent->data[i];

       for(i = 0;i < 9;i++)

              if(child->data[i] == 0)break;

       if(n==0)

              loc = i%3+(i/3 - 1)*3;

       else if(n==1)

              loc = i%3+(i/3 + 1)*3;

       else if(n==2)

              loc = i%3-1+(i/3)*3;

       else

              loc = i%3+1+(i/3)*3;

       temp = child->data[loc];

       child->data[i] = temp;

       child->data[loc] = 0;

}

void Spread(Lnode * suc, Lstack * Open, Lstack * Closed, Node goal, int m)

{//扩展后继节点总函数

       int i;

       Node * child;

       for(i = 0; i < 4; i++)

       {

              if(Canspread(**suc, i+1))                               //判断某个方向上的子节点可否扩展

              {

                            child = (Node *) malloc(sizeof(Node));          //扩展子节点

                   child->g = (*suc)->g +1;                        //算子节点的g值

                   child->parent = (*suc);                         //子节点父指针指向父节点

                   Spreadchild(child, i);                          //向该方向移动空格生成子节点

                  if(BelongProgram(&child, Open, Closed, goal, m)) // 判断子节点是否属于OPEN或CLOSED表并作出相应的处理

                                   free(child);

              }

       }

}

///////////////////////扩展后继节点部分的函数-结束//////////////////////////////////

Node * Process(Lnode * org, Lnode * goal, Lstack * Open, Lstack * Closed, int m)

{//总执行函数

       while(1)

       {

              if((*Open)->next == NULL)return NULL;                    //判断OPEN表是否为空,为空则失败退出

           Node * minf = Minf(Open);                                //从OPEN表中取出f值最小的节点

              Putinto(minf, Closed);                                   //将节点放入CLOSED表中

           if(Equal(minf, *goal))return minf;                       //如果当前节点是目标节点,则成功退出

        Spread(&minf, Open, Closed, **goal, m);                 //当前节点不是目标节点时扩展当前节点的后继节点

       }

}

int Shownum(Node * result)

{//递归显示从初始状态到达目标状态的移动方法

       if(result == NULL)return 0;

       else

       {

              int n = Shownum(result->parent);

              printf("第%d步:",n);

              for(int i = 0; i < 3; i++)

                     {

                            printf("\n");

                            for(int j = 0; j < 3; j++)

                            {

                                   if(result->data[i*3+j] != 0)

                                          printf(" %d ",result->data[i*3+j]);

                                   else printf(" 0 ");

                            }

                     }

              printf("\n");

              return n+1;

       }

}

void Checkinput(Node *suc)

{//检查输入

       int i = 0,j = 0,flag = 0;

       char c;

       while(i < 9)

       {

              while(((c = getchar()) != 10))

              {

                     if(c == ' ')                    

                     {

                            if(flag >= 0)flag = 0;

                     }

                     else if(c >= '0' && c <= '8')

                     {

                            if(flag == 0)

                            {

                                   suc->data[i] = (c-'0');

                                   flag = 1;

                                   for(j =0; j < i; j++)

                                          if(suc->data[j] == suc->data[i])flag = -2;                                

                                i++;

                            }

                            else if(flag >= 0)flag = -1;

                     }

                     else

                            if(flag >= 0)flag = -1;

              }

              if(flag <0  || i < 9)

              {

                     if(flag < 0)

                     {

                            if(flag == -1)printf("含有非法字符或数字!\n请重新输入:\n");

                            else if(flag == -2)printf("输入的数字有重复!\n请重新输入:\n");

                     }

                     else if(i < 9)printf("输入的有效数字不够!\n请重新输入:\n");

                     i = 0;

                     flag = 0;

              }

       }

}

int meassure(Lstack  s)

{

       int k=0;

       while((s->next)!=NULL)

       {

              k++;

              s=s->next;

       }

       return k;

}

void main()

{//主函数                                                             //初始操作,建立open和closed表

       Lstack Open = (Stack *) malloc(sizeof(Stack));

       Open->next = NULL;

       Lstack Closed = (Stack *) malloc(sizeof(Stack));

       Closed->next = NULL;

       Node * org = (Node *) malloc(sizeof(Node));

       org->parent = NULL;                                        //初始状态节点

       org->f =1;

       org->g =1;

    Node * goal = (Node *) malloc(sizeof(Node));               //目标状态节点

       Node * result;

       int m;

       char c;

       int k;

       printf("=================================\n");

       printf("说明:状态矩阵由0-8 九个数字表示,\n请依次按照九宫格上的行列顺序输入,每个数字间用空格隔开。\n");

    printf("=================================\n");

       printf("请输入初始状态(0-8 9个数字以空格隔开回车表示输入结束):\n");

       Checkinput(org);

       printf("请输入目标状态(0-8 9个数字以空格隔开回车表示输入结束):\n");

       Checkinput(goal);

       if(Canslove(org, goal))

       {//A*算法开始,先将初始状态放入OPEN表                                                      

               printf("请选择:1.按w(n)搜索 2.按p(n)搜索 \n");

               scanf("%d",&m);

               while((c = getchar()) != 10);

               printf("搜索中,请耐心等待(如果您觉得时间太久请重新执行程序并输入更快的速度,默认值为)......\n");

            Putinto(org,&Open);

          result = Process(&org, &goal, &Open, &Closed, m);  //进行剩余的操作

               printf("总步数:%d",Shownum(result)-1);

            printf("\n");

               k=meassure(Closed);

               printf("扩展节点数:\n");

               printf("%d\n",k);

               printf("Press Enter key to exit!");

               while((c = getchar()) != 10);

       }

       else

              printf("程序认定该起始状态无法道达目标状态!\n");

}

更多相关推荐:
八数码实验报告

利用人工智能技术解决八数码游戏问题1八数码游戏问题简介九宫排字问题又称八数码问题是人工智能当中有名的难题之一问题是在33方格盘上放有八个数码剩下第九个为空每一空格其上下左右的数码可移至空格问题给定初始位置和目标...

人工智能实验报告 八数码问题

实验一启发式搜索算法姓名徐维坚学号2220xx3484日期20xx629一实验目的熟练掌握启发式搜索A算法及其可采纳性二实验内容使用启发式搜索算法求解8数码问题1编制程序实现求解8数码问题A算法采用估价函数wn...

八数码实验报告53

华中师范大学计算机学院实验报告书实验题目:八数码问题求解课程名称:人工智能主讲教师:**班级:试验时间:1.问题描述:八数码问题也称为九宫问题。在33的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋…

C语言解八数码问题之人工智能实验报告

人工智能上机实验基于人工智能的状态空间搜索策略研究八数码问题求解一实验软件TC20或VC60编程语言或其它编程语言二实验目的1熟悉人工智能系统中的问题求解过程2熟悉状态空间的盲目搜索和启发式搜索算法的应用3熟悉...

八数码问题人工智能实验报告

基于人工智能的状态空间搜索策略研究八数码问题求解(一)实验软件TC2.0或VC6.0编程语言或其它编程语言(二)实验目的1.熟悉人工智能系统中的问题求解过程;2.熟悉状态空间的盲目搜索和启发式搜索算法的应用;3…

人工智能实验报告,包括八数码问题八皇后问题和tsp问题

八数码问题(一)问题描述在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。这些数码可以在棋盘上移动,其移动规则是:与空格相邻的数码方格可以移入空格。现在的问题是:…

昆明理工大学 八数码实验报告

昆明理工大学信息工程与自动化学院学生实验报告20xx20xx学年第1学期课程名称人工智能及其应用开课实验室信自楼50420xx年11月26日一上机目的及内容1上机内容求解八数码问题问题描述八数码难题问题描述在3...

八数码问题求解--实验报告

实验报告一实验问题八数码问题求解二实验软件VC60编程语言或其它编程语言三实验目的1熟悉人工智能系统中的问题求解过程2熟悉状态空间的盲目搜索和启发式搜索算法的应用3熟悉对八数码问题的建模求解及编程语言的应用四实...

人工智能A算法八数码报告

人工智能课程设计报告题目A算法解决八数码问题专业计算机软件与理论18数码问题11问题描述八数码问题是指这样一种游戏将分别标有数字1238的八块正方形数码牌任意地放在一块33的数码盘上放牌时要求不能重叠于是在33...

实验一 八数码

昆明理工大学信息工程与自动化学院学生实验报告20xx20xx学年第1学期课程名称人工智能及其应用开课实验室信自楼44420xx年12月30日一上机目的及内容1上机内容求解八数码问题问题描述八数码难题问题描述在3...

人工智能实验 八数码

实验一图搜索策略之八数码问题1实验目的1加深对各种图搜索策略概念的理解2进一步了解启发式搜索剪枝等概念3比较并分析各种图搜索策略的实质2实验设计八数码游戏八数码问题描述为在33组成的九宫格棋盘上摆有八个将牌每一...

A星算法求解八数码技术报告

A算法求解八数码问题open表closed表数据结构的选择1把s放入open表记fh令closed为空表2重复下列过程直到找到目标节点为止若open表为空表则宣告失败3选取open表中未设置过的具有最小f值的节...

八数码实验报告(23篇)