人工智能导论实验一 基于图搜索技术的八数码问题求解

广州大学学生实验报告

开课学院及实验室:计算机科学与工程实验室 2020年10月14日

(***报告只能为文字和图片,老师评语将添加到此处,学生请勿作答***)

一、实验内容

1. 分别用广度优先搜索策略、深度优先搜索策略和启发式搜索算法(至少两种)求解八数码问题;分析估价函数对启发式搜索算法的影响;探究讨论各个搜索算法的特点。

二、实验设备

1. 实验设备:计算机;

2. 平台:Windows操作系统,Visual C++ 6.0 / Python Anaconda

三、实验步骤

1. 随机生成一个八数码问题分布,设计一个可解的目标状态(要求棋盘9个位置都不同)

2. 分别用广度优先搜索策略、深度优先搜索策略和至少两种启发式搜索算法求解八数码问题

3. 分析估价函数对启发式搜索算法的影响

4. 探究讨论各个搜索算法的特点

四、分析说明(包括核心代码及解释)

广度优先搜索:

首先创建一个结构体node,来记录节点移动方向和扩展的节点。

struct node

{

int ab[3][3];//节点

int direction;//方向

};

struct node sh[102], end;

int count = 1;

然后创建一个init函数来初始化棋盘起始状态和目标状态,使用for语句填写棋盘数字

用loction函数确定0节点的位置,通过for语句和if语句判断sh[num].ab[i / 3][i % 3] == 0,即可得到0节点的位置

Sign函数用来获取棋盘状态,将当前棋盘数字顺序生成一个数,即可得知棋盘状态。

Mobile函数用来移动0节点,先用loction函数获取0节点的位置,再通过if语句来判断0节点位置和所能移动方向,然后进行移动。

Display函数使用for语句来打印当前棋盘。

Search函数使用display函数来打印从初始状态移动到目标状态的中间状态棋盘,在while(1)语句下利用mobile函数移动0节点,直到目标状态找到或者超过寻找次数。

#include

#include

struct node

{

int ab[3][3];//节点

int direction;//方向

};

struct node sh[102], end;

int count = 1;

void init()

{

printf("输入起始棋盘的状态:\n");

int i, j;

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

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

scanf("%d", &sh[0].ab[i][j]);

sh[0].direction = -1;

printf("输入目标棋盘的状态:\n");

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

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

scanf("%d", &sh[101].ab[i][j]);

sh[101].direction = -1;

printf("中间状态:\n");

}

//找出0的位置

int loction(int num)

{

int i;

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

if (sh[num].ab[i / 3][i % 3] == 0) return i;

}

//获取棋盘状态

long long sign(int num)

{

long long sum;

sum = sh[num].ab[0][0] * 100000000 + sh[num].ab[0][1] * 10000000 + sh[num].ab[0][2] * 1000000 + sh[num].ab[1][0] * 100000 + sh[num].ab[1][1] * 10000 + sh[num].ab[1][2] * 1000 + sh[num].ab[2][0] * 100 + sh[num].ab[2][1] * 10 + sh[num].ab[2][2];

return sum;

}

//移动0节点

void mobile(int num)

{

int temp;

int loc;

int up = 1, down = 1, left = 1, right = 1;

loc = loction(num);

int stand = sh[num].direction;

//direction的0 1 2 3分别代表左上右下

if (loc / 3 != 0 && stand != 1)

{

sh[count] = sh[num];

temp = sh[count].ab[loc / 3][loc % 3];

sh[count].ab[loc / 3][loc % 3] = sh[count].ab[loc / 3 - 1][loc % 3];

sh[count].ab[loc / 3 - 1][loc % 3] = temp;

sh[count].direction = 3;

count++;

};

if (loc / 3 != 2 && stand != 3)

{

sh[count] = sh[num];

temp = sh[count].ab[loc / 3][loc % 3];

sh[count].ab[loc / 3][loc % 3] = sh[count].ab[loc / 3 + 1][loc % 3];

sh[count].ab[loc / 3 + 1][loc % 3] = temp;

sh[count].direction = 1;

count++;

}

if (loc % 3 != 0 && stand != 0)

{

sh[count] = sh[num];

temp = sh[count].ab[loc / 3][loc % 3];

sh[count].ab[loc / 3][loc % 3] = sh[count].ab[loc / 3][loc % 3 - 1];

sh[count].ab[loc / 3][loc % 3 - 1] = temp;

sh[count].direction = 2;

count++;

}

if (loc % 3 != 2 && stand != 2)

{

sh[count] = sh[num];

temp = sh[count].ab[loc / 3][loc % 3];

sh[count].ab[loc / 3][loc % 3] = sh[count].ab[loc / 3][loc % 3 + 1];

sh[count].ab[loc / 3][loc % 3 + 1] = temp;

sh[count].direction = 0;

count++;

}

}

//打印当前棋盘

void display(int num)

{

int i, j;

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

{

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

printf("%d ", sh[num].ab[i][j]);

printf("\n");

}

}

//寻找目标状态

int search()

{

int i = 0;

while (1)

{

printf("\n");

display(i);

printf("\n");

if (i == 100)

{

printf("超出了上限次数\n");

return 0;

}

if (sign(i) == sign(101))

{

printf("在第%d次找到了\n", i);

display(i);

return i;

}

mobile(i);

i++;

}

}

int main()

{

init();

search();

system("pause");

}

宽度优先搜索:

创建一个结构体Octal,其中的arr[4][4]用来存储八数码

To_number函数将八数码棋盘中的数据转为数字存储。

Up函数用来移动0节点,同时判断0节点是否能向上移动

Down函数用来判断0节点是否能向下移动

Left函数用来判断0节点是否能向左移动

Right函数用来判断0节点是否能向右移动

主函数中用while(!open.empty())语句来循环搜索目标状态,用if语句判断当前状态若为目标状态则break 跳出循环,然后打印寻找目标状态过程的中间状态

#include

#include

using namespace std;

struct Octal

{

int arr[4][4]; // 存储八数码

int parent; // 父亲的值

int current; // 当前的值

int depth; // 当前深度

};

int to_number(int[4][4]);

bool up(int[4][4]);

bool down(int[4][4]);

bool left(int[4][4]);

bool right(int[4][4]);

int main()

{

int arr[4][4] = { 0 }; // 存储当前八数码

vector open; // open表

vector closed; // closed表

int depth; // 深度

Octal octal; // 八数码

cout <<"请输入起始棋盘状态:"<< endl;

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

{

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

{

cin >> arr[i][j];

octal.arr[i][j] = arr[i][j];

}

}

cout <<"请输入深度:"<< endl;

cin >> depth;

cout <<"中间状态:"<< endl;

octal.parent = 0;

octal.current = to_number(arr);

octal.depth = 0;

open.push_back(octal);

int goal = 123804765; // 最终的八数码值

bool flag = false; // 成功解决为true,失败为false

Octal temp;

int count = 1;

while (!open.empty())

{

temp.current = open[open.size() - 1].current;

temp.parent = open[open.size() - 1].parent;

temp.depth = open[open.size() - 1].depth;

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

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

temp.arr[i][j] = open[open.size() - 1].arr[i][j];

open.pop_back();

closed.push_back(temp);

if (temp.current == goal)

{

flag = true;

break;

}

if (temp.depth >= depth)

{

continue;

}

Octal produce[4]; // 四个可能生成的八数码数组

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

{

produce[i].parent = temp.current;

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

for (int k = 1; k <= 3; k++)

produce[i].arr[j][k] = temp.arr[j][k];

produce[i].depth = temp.depth + 1;

}

bool flagProduce[4][2]; // 四个八数码对应的标志,0为open中是否含有,1位closed中是否含有

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

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

flagProduce[i][j] = true;

if (up(produce[0].arr))

{

produce[0].current = to_number(produce[0].arr);

for (int i = 0; i < open.size(); i++)

if (open[i].current == produce[0].current)

{

flagProduce[0][0] = false;

break;

}

if (flagProduce[0][0])

{

for (int i = 0; i < closed.size(); i++)

if (closed[i].current == produce[0].current)

{

flagProduce[0][1] = false;

break;

}

if (flagProduce[0][1])

open.push_back(produce[0]);

}

}

if (down(produce[1].arr))

{

produce[1].current = to_number(produce[1].arr);

for (int i = 0; i < open.size(); i++)

if (open[i].current == produce[1].current)

{

flagProduce[1][0] = false;

break;

}

if (flagProduce[1][0])

{

for (int i = 0; i < closed.size(); i++)

if (closed[i].current == produce[1].current)

{

flagProduce[1][1] = false;

break;

}

if (flagProduce[1][1])

open.push_back(produce[1]);

}

}

if (left(produce[2].arr))

{

produce[2].current = to_number(produce[2].arr);

for (int i = 0; i < open.size(); i++)

if (open[i].current == produce[2].current)

{

flagProduce[2][0] = false;

break;

}

if (flagProduce[2][0])

{

for (int i = 0; i < closed.size(); i++)

if (closed[i].current == produce[2].current)

{

flagProduce[2][1] = false;

break;

}

if (flagProduce[2][1])

open.push_back(produce[2]);

}

}

if (right(produce[3].arr))

{

produce[3].current = to_number(produce[3].arr);

for (int i = 0; i < open.size(); i++)

if (open[i].current == produce[3].current)

{

flagProduce[3][0] = false;

break;

}

if (flagProduce[3][0])

{

for (int i = 0; i < closed.size(); i++)

if (closed[i].current == produce[3].current)

{

flagProduce[3][1] = false;

break;

}

if (flagProduce[3][1])

open.push_back(produce[3]);

}

}

}

if (flag)

{

vector answer;

answer.push_back(temp);

int parent = temp.parent;

while (parent != 0)

{

for (int j = 0; j < closed.size(); j++)

{

if (closed[j].current == parent)

{

temp.current = closed[j].current;

temp.depth = closed[j].depth;

temp.parent = closed[j].parent;

for (int k = 1; k <= 3; k++)

{

for (int m = 1; m <= 3; m++)

{

temp.arr[k][m] = closed[j].arr[k][m];

}

}

answer.push_back(temp);

parent = closed[j].parent;

break;

}

}

}

for (int i = answer.size() - 1; i >= 0; i--)

{

if(i<=0)

{cout <<"第"<< answer.size() - i - 1 <<"次找到了"<< endl; }

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

{

for (int k = 1; k <= 3; k++)

{

cout << answer[i].arr[j][k] <<" ";

}

cout << endl;

}

cout << endl;

}

}

else

{

cout <<"在深度限制内的所有结果搜索完毕,没有答案!"<< endl;

}

system("pause");

}

int to_number(int arr[4][4])

{

// 将八数码矩阵中的数据转换为数字,方便存储和比较

// 从左到右,从上至下,按照从1到9递增,1为亿位,……,9为个位

int index = 100000000;

long long result = 0;

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

{

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

{

result += arr[i][j] * index;

index /= 10;

}

}

return result;

}

bool up(int arr[4][4])

{

// 空格向上

int i, j; // 空格的位置为(i, j)

bool flag = false;

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

{

for (j = 1; j <= 3; j++)

if (arr[i][j] == 0)

{

flag = true;

break;

}

if (flag)

break;

}

if (i == 1)

return false; // 此时无法向上else

{

arr[i][j] = arr[i - 1][j];

arr[i - 1][j] = 0;

}

return true;

}

bool down(int arr[4][4])

{

// 空格向下

int i, j; // 空格的位置为(i, j)

bool flag = false;

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

{

for (j = 1; j <= 3; j++)

if (arr[i][j] == 0)

{

flag = true;

break;

}

if (flag)

break;

}

if (i == 3)

return false; // 此时无法向下else

{

arr[i][j] = arr[i + 1][j];

arr[i + 1][j] = 0;

}

return true;

}

bool left(int arr[4][4])

{

// 空格向左

int i, j; // 空格的位置为(i, j)

bool flag = false;

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

{

for (j = 1; j <= 3; j++)

if (arr[i][j] == 0)

{

flag = true;

break;

}

if (flag)

break;

}

if (j == 1)

return false; // 此时无法向左else

{

arr[i][j] = arr[i][j - 1];

arr[i][j - 1] = 0;

}

return true;

}

bool right(int arr[4][4])

{

// 空格向右

int i, j; // 空格的位置为(i, j)

bool flag = false;

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

{

for (j = 1; j <= 3; j++)

if (arr[i][j] == 0)

{

flag = true;

break;

}

if (flag)

break;

}

if (j == 3)

return false; // 此时无法向右else

{

arr[i][j] = arr[i][j + 1];

arr[i][j + 1] = 0;

}

return true;

}

启发式搜索:

首先创建一个结构体Node。struct Node

{

string father;//父节点的id

string id;//当前状态

int f, g = 0, h;//分别对应估价函数中的f(n),g(n),h(n)

int value[3][3];//存储八数码

};

GetID函数用来获取当前状态。

CalcuH函数用来判断0节点能移动的方向并计算下一节点的估价函数值Outprint函数用来打印初始状态移动0节点,到达目标状态的过程。

Move函数用来移动0节点

Seach函数用来寻找目标状态

主函数中先设定初始状态和目标状态,然后动用上述函数打印出中间过程#include

#include

#include

#include

#include

#include

using namespace std;

struct Node

{

string father;//父节点的id

string id;//当前状态

int f, g = 0, h;//分别对应估价函数中的f(n),g(n),h(n)

int value[3][3];//存储八数码

};

//获得当前状态

string getID(int *value)

{

stringstream ss;

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

{

ss <

}

return ss.str();

}

//判断0节点能移动的方向,计算下一节点的估价函数值

int calcuH(int *value)

{

int h = 0;

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

{

int num = value[i] - 1;

if (num == -1)continue;

int nowx = i % 3, nowy = i / 3;

int goalx = num % 3, goaly = num / 3;

h += abs(nowx - goalx) + abs(nowy - goaly);

}

return h;

}

bool operator == (const Node & obj1, const Node & obj2) {

return obj1.id ==obj2.id;

}

bool cmpH(Node i, Node j) { return (i.h > j.h); }

vector close;

vector open;

static int oldH = 999999;

Node bestResult;

int moveMat[9][4] = {

{0,1,1,0},

{0,1,1,1},

{0,0,1,1},

{1,1,1,0},

{1,1,1,1},

{1,0,1,1},

{1,1,0,0},

{1,1,0,1},

{1,0,0,1}

};//move mat ,list as up right down left

void outPrint(Node result)

{

vector::iterator iter;

stack outStack;

outStack.push(result);

int time = -1;

while (result.father !="start")

{

result.id =result.father;

iter = find(close.begin(), close.end(), result);

if (iter != close.end())

{

result=*iter;

outStack.push(result);

}

else

{

cout <<"program error in outprint"<< endl;

break;

}

}

Node oneRow[5];

int p = 0, changeRow = 5;

while (!outStack.empty())

{

oneRow[p++] = outStack.top();

outStack.pop();

time++;

if (p == changeRow)

{

p = 0;

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

{

for (int col = 0; col < changeRow; col++)

{

cout << oneRow[col].value[row][0] << oneRow[col].value[row][1] << oneRow[col].value[row][2];

if (row == 1)

cout <<" -> ";

else

cout <<" ";

}

cout << endl;

}

cout << endl;

}

}

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

{

for (int col = 0; col < p; col++)

{

cout << oneRow[col].value[row][0] << oneRow[col].value[row][1] <<

oneRow[col].value[row][2];

if (row == 1)

cout <<" -> ";

else

cout <<" ";

}

cout << endl;

}

cout << endl;

cout <<"在第"<< time <<"次找到了"<< endl;

oldH = 999999;

system("pause");

}

void finalOutPrint()

{

if (bestResult.father !="NO")

{

cout <<"----This is Finally best result"<< endl;

outPrint(bestResult);

cout <<"----This is Finally best result"<< endl;

cout <<"Search all node finish"<< endl;

}

else

cout <<"No result,is error"<< endl;

}

//移动0节点

void move(Node node, int blockSite, int direction)

{

int moveSite, oldH = node.h, *pvalue = (int*)node.value;

switch (direction)

{

case 0:

moveSite = blockSite - 3;

break;

case 1:

moveSite = blockSite + 1;

break;

case 2:

moveSite = blockSite + 3;

break;

case 3:

moveSite = blockSite - 1;

break;

default:

cout <<"error!!"<< endl;

exit(1);

break;

}

{

int temp;

temp = pvalue[blockSite];

pvalue[blockSite] = pvalue[moveSite];

pvalue[moveSite] = temp;

}

node.father =node.id;

node.id = getID((int*)node.value);

node.g++;

if (node.id =="123456780")

{

outPrint(node);

if (node.g < bestResult.g)

{

bestResult.father =node.father;

bestResult.g = node.g;

}

}

else

{

node.h = calcuH((int*)node.value);

node.f = node.g + node.h;

vector::iterator iter;

iter = find(close.begin(), close.end(), node);

if (iter != close.end())

{

if (iter->g > node.g)

{

iter->father =node.father;

iter->g = node.g;

iter->f = node.f;

}

}

else

{

iter = find(open.begin(), open.end(), node);

if (iter != open.end())

{

if (iter->g > node.g)

人工智能实验报告

****大学 人工智能基础课程实验报告 (2011-2012学年第一学期) 启发式搜索王浩算法 班级: *********** 学号: ********** 姓名: ****** 指导教师: ****** 成绩: 2012年 1 月 10 日

实验一 启发式搜索算法 1. 实验内容: 使用启发式搜索算法求解8数码问题。 ⑴ 编制程序实现求解8数码问题A *算法,采用估价函数 ()()()() w n f n d n p n ??=+???, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数; ()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。 ⑵ 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是()p n 的上界的()h n 的定义,并测试使用该估价函数是否使算法失去可采纳性。 2. 实验目的 熟练掌握启发式搜索A *算法及其可采纳性。 3. 实验原理 使用启发式信息知道搜索过程,可以在较大的程度上提高搜索算法的时间效率和空间效率; 启发式搜索的效率在于启发式函数的优劣,在启发式函数构造不好的情况下,甚至在存在解的情形下也可能导致解丢失的现象或者找不到最优解,所以构造一个优秀的启发式函数是前提条件。 4.实验内容 1.问题描述 在一个3*3的九宫格 里有1至8 八个数以及一个空格随机摆放在格子中,如下图: 初始 状 态 目标状态 现需将图一转化为图二的目标状态,调整的规则为:每次只能将空格与其相邻的一个数字进行交换。实质是要求给出一个合法的移动步骤,实现从初始状态到目标状态的转变。

人工智能实验1-2

试验1:用谓词表示猴子摘香蕉问题 实验内容: 利用一阶谓词逻辑求解猴子摘香蕉问题:房内有一个猴子,一个箱子,天花板上挂了一串香蕉,其位置如图所示,猴子为了拿到香蕉,它必须把箱子搬到香蕉下面,然后再爬到箱子上。请定义必要的谓词,列出问题的初始化状态(即下图所示状态),目标状态(猴子拿到了香蕉,站在箱子上,箱子位于位置b)。写出所用谓词的定义,并给出每个谓词的功能及变量的个体域,然后编程实现。 实验目的: 通过此实验加深对谓词逻辑和谓词知识表示的理解。 实验报告要求: 所撰写的实验报告必须包含以下内容: 1. 所用谓词的定义以及每个谓词的功能及变量的个体域; 2. 实验结果;(可截图) 3. 提供全部源程序及软件的可执行程序。(打印) 实验2:八数码问题 实验内容: 八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。 2 5 4 1 2 3 3 7 8 4 1 8 6 7 6 5 (a) 初始状态(b) 目标状态 请任选一种盲目搜索算法(深度优先搜索或宽度优先搜索)或任选一种启发式搜索方法(A 算法或A* 算法)编程求解八数码问题(初始状态任选),并对实验结果进行分析,得出合理的结论。 实验目的: 1. 熟悉人工智能系统中的问题求解过程; 2. 熟悉状态空间的盲目搜索和启发式搜索算法的应用; 3. 熟悉对八数码问题的建模、求解及编程语言的应用。 实验报告要求 所撰写的实验报告必须包含以下内容: 1. 算法基本原理和流程框图; 2. 基本数据结构分析和实现;

人工智能实验报告(八皇后)

《人工智能导论》上机实验 八皇后问题求解 班级:10011207 姓名:盛家铭 学号:2012302532

图搜索策略实验 八皇后问题求解 一、实验软件 codeblocks 环境 二、 实验目的 通过实验能对搜索策略有更深刻的理解 熟悉人工智能系统中的问题求解过程; 熟悉状态空间的盲目搜索和启发式搜索算法的应用; 熟悉对八数码问题的建模、求解及编程语言的应用。 三、 需要的知识 熟悉人工智能系统中的问题求解过程; 熟悉状态空间的盲目搜索和启发式搜索算法的应用; 熟悉对八数码问题的建模、求解及编程语言的应用。 四、 实验数据及步骤 1、实验内容 八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后。为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n 皇后摆放问题:这时棋盘的大小变为n ×n ,而皇后个数也变成n 。当且仅当 n = 1 或 n ≥ 4 时问题有解。 2、程序函数调用图 主函数 sesearch 递归调用 output canplace 判断能否放置皇后 输出最后结果

3、实验步骤 采用算法的基本原理,使用深度优先搜索算法,对各层次的各位置进行搜索。 定义一个一维数组a[8],其中a[i]的值表示第i行的皇后的位置。由于结果情况种类较多,所以特地在程序中运用文件输出,新建一个TXT文档用于存储结果,使得最后的结果都输出在TXT文件中。 4、实验源程序 用于输出最后结果 #include int n=1; FILE *fp; int canplace(int m,int i,int a[8]) {//m行,i列 int j=0; while(j

人工智能导论:状态空间搜索实验—八数码问题求解

昆明理工大学信息工程与自动化学院学生实验报告 ( 2014—— 2015 学年 第 一 学期 ) 课程名称:人工智能导论 开课实验室: 年 月 日 一、实验内容和要求 八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。 例如: (a) 初始状态 (b) 目标状态图1 八数码问题示意图 请任选一种盲目搜索算法(广度优先搜索或深度优先搜索)或任选一种启发式搜索方法(全局择优搜索,加权状态图搜索,A 算法或 A * 算法)编程求解八数码问题(初始状态任选)。选择一个初始状态,画出搜索树,填写相应的OPEN 表和CLOSED 表,给出解路径,对实验结果进行分析总结,得出结论。 实验报告内容格式要求:XXXXXXXXXXXX (中文:宋体,小四;英文:Times New Roman )。

二、实验目的 1. 熟悉人工智能系统中的问题求解过程; 2. 熟悉状态空间的盲目搜索和启发式搜索算法的应用; 3. 熟悉对八数码问题的建模、求解及编程语言的应用。 三、实验算法 启发函数设定 由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零,因此可以把数码不同的位置个数作为标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息来扩展节点的选择,减少搜索范围,提高搜索速度。 2、数据结构与算法设计 数码结构体 typedef struct node //八数码结构体 { int form[N][N]; //数码组 int evalue; //评估值,差距 int udirec; //所屏蔽方向,防止往回推到上一状态,1上2下3左4右 struct node *parent; //父节点 }Graph; Graph *Qu[MAX];//队列 Graph *St[MAX];//堆栈 搜索过程:(搜索采用广度搜索方式,利用待处理队列辅助,逐层搜索(跳过劣质节点)) a、把初始数码组压入队列; b、从队列中取出一个数码组节点; c、扩展子节点,即从上下左右四个方向移动空格,生成相应子节点: d、对子节点数码组作评估,是否为优越节点,即其评估值是否小于等于其父节点加一,是则将其压入队,否则抛弃。 e、判断压入队的子节点数码组(优越点)的评估值,为零则表示搜索完成,退出搜索; f、跳到步骤2; 四、程序框图

人工智能-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

八数码问题-实验报告(含源码)

人工智能基础实验报告 题目:八数码问题

一、内容 (2) 二、目的 (2) 三、实验设计思想和流程 (2) 四、主要数据结构及符号说明 (3) 五、程序初值及运行结果 (5) 附录(源代码及注释) (6)

一、内容 八数码问题由8个编号1~8并放在3*3方格棋盘上的可走动的棋子组成。棋盘上有一个格是空的,以便可以让空格周围的棋子走进空格,这也可以理解为移动空格。给出起始状态和目标状态。用A*算法求解出移动的路径。 二、目的 1、学会用状态空间法来进行知识表示 2、理解A*算法 三、实验设计思想和流程 1.八数码问题的状态表示 八数码问题的一个状态就是八个数字在棋盘上的一种放法。每个棋子用它上面所标的数字表示,并用0表示空格,这样就可以将棋盘上棋子的一个状态存储在一个二维数组中。 2、结点扩展规则 搜索就是按照一定规则扩展已知结点,直到找到目标结点或所有结点都不能扩展为止。 八数码问题的结点扩展应当遵守棋子的移动规则。按照棋子移动的规则,每一次可以将一个与空格相邻棋子移动到空格中,实际上可以看作是空格作相反移动。空格移动的方向可以是右、下、左、上,当然不能移出边界。 3、A*算法 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到目标结点的最佳路径的估计代价。在这里

人工智能导论实验一 基于图搜索技术的八数码问题求解

广州大学学生实验报告 开课学院及实验室:计算机科学与工程实验室 2020年10月14日 (***报告只能为文字和图片,老师评语将添加到此处,学生请勿作答***) 一、实验内容 1. 分别用广度优先搜索策略、深度优先搜索策略和启发式搜索算法(至少两种)求解八数码问题;分析估价函数对启发式搜索算法的影响;探究讨论各个搜索算法的特点。 二、实验设备 1. 实验设备:计算机; 2. 平台:Windows操作系统,Visual C++ 6.0 / Python Anaconda 三、实验步骤 1. 随机生成一个八数码问题分布,设计一个可解的目标状态(要求棋盘9个位置都不同) 2. 分别用广度优先搜索策略、深度优先搜索策略和至少两种启发式搜索算法求解八数码问题 3. 分析估价函数对启发式搜索算法的影响 4. 探究讨论各个搜索算法的特点 四、分析说明(包括核心代码及解释) 广度优先搜索: 首先创建一个结构体node,来记录节点移动方向和扩展的节点。 struct node { int ab[3][3];//节点

int direction;//方向 }; struct node sh[102], end; int count = 1; 然后创建一个init函数来初始化棋盘起始状态和目标状态,使用for语句填写棋盘数字 用loction函数确定0节点的位置,通过for语句和if语句判断sh[num].ab[i / 3][i % 3] == 0,即可得到0节点的位置 Sign函数用来获取棋盘状态,将当前棋盘数字顺序生成一个数,即可得知棋盘状态。 Mobile函数用来移动0节点,先用loction函数获取0节点的位置,再通过if语句来判断0节点位置和所能移动方向,然后进行移动。 Display函数使用for语句来打印当前棋盘。 Search函数使用display函数来打印从初始状态移动到目标状态的中间状态棋盘,在while(1)语句下利用mobile函数移动0节点,直到目标状态找到或者超过寻找次数。 #include #include struct node { int ab[3][3];//节点 int direction;//方向 }; struct node sh[102], end; int count = 1; void init() { printf("输入起始棋盘的状态:\n"); int i, j; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) scanf("%d", &sh[0].ab[i][j]); sh[0].direction = -1; printf("输入目标棋盘的状态:\n"); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) scanf("%d", &sh[101].ab[i][j]); sh[101].direction = -1; printf("中间状态:\n"); }

采用A算法解决八数码问题

. 人工智能实验一报告题目:采用A*算法解决八数码问题 姓名:张博涵 学号: 081110317 专业:信息与计算科学 提交日期: 2014-05-22

目录 1问题描述........................................................................................................................... - 2 - 1.1待解决问题的解释............................................................................................... - 2 - 1.2问题的搜索形式描述............................................................................................ - 2 - 1.3解决方案介绍(原理)........................................................................................ - 3 - 2算法介绍........................................................................................................................... - 4 - 2.1A*搜索算法一般介绍............................................................................................ - 4 - 2.2 算法伪代码........................................................................................................... - 4 - 3算法实现........................................................................................................................... - 5 - 3.1 实验环境与问题规模........................................................................................... - 5 - 3.2 数据结构............................................................................................................... - 5 - 3.3 实验结果............................................................................................................... - 5 - 3.4系统中间及最终输出结果.................................................................................... - 7 - 4参考文献........................................................................................................................... - 8 - 5附录—源代码及其注释................................................................................................... - 8 -

八数码问题A算法的实现及性能分析

八数码问题A*算法的实现及性能分析 计算机科学与技术学院 专业:计算机科学与技术 161210404 杨凯迪

目录 一、8数码问题 (3) 1.问题描述 (3) 2.八数码问题形式化描述 (3) 3.解决方案 (3) 二、A*算法 (4) 1.A*搜索算法一般介绍 (4) 2. A*算法的伪代码 (5) 3. 建立合适的启发式 (6) 三、算法实现及性能比较 (6) 四、算法性能分析 (8) 五、结论 (9) 六、参考文献 (10) 附录 (10)

一、8数码问题 1.问题描述 八数码问题是指这样一种游戏:将分别标有数字1,2,3,…,8 的八块正方形数码牌任意地放在一块3×3 的数码盘上。放牌时要求不能重叠。于是,在3×3 的数码盘上出现了一个空格。现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,不断移动该空格方块以使其和相邻的方块互换,直至达到所定义的目标状态。空格方块在中间位置时有上、下、左、右4个方向可移动,在四个角落上有2个方向可移动,在其他位置上有3个方向可移动,问题描述如图1-1所示 初始状态过渡状态最终状态 图1-1 八数码问题执行过程 2.八数码问题形式化描述 初始状态: 初始状态向量:规定向量中各分量对应的位置,各位置上的数字。把3×3的棋盘按从左到右,从上到下的顺序写成一个一维向量。我们可以设定初始状态:<1,5,2,4,0,3,6,7,8> 后继函数: 按照某种规则移动数字得到的新向量。例如: <1,5,2,4,0,3,6,7,8> <1,0,2,4,5,3,6,7,8> 目标测试: 新向量是都是目标状态。即<1,2,3,4,5,6,7,8,0>是目标状态? 路径耗散函数: 每次移动代价为1,每执行一条规则后总代价加1。 3.解决方案 该问题是一个搜索问题。它是一种状态到另一种状态的变换。要解决这个问

八数码 人工智能实验报告

八数码人工智能实验报告 八数码人工智能实验报告 引言: 八数码是一种经典的数学问题,也是人工智能领域中常用的实验题目之一。本 次实验旨在通过使用搜索算法解决八数码问题,探讨人工智能在解决复杂问题 上的应用。 一、问题描述: 八数码问题是一种数字排列游戏,使用一个3x3的方格,其中8个方格上各有 一个数字,剩下一个方格为空白。通过移动数字方格,最终将数字按照从小到 大的顺序排列,空白方格位于最后一个位置。例如,初始状态为: 1 2 3 8 4 7 6 5 目标状态为: 1 2 3 4 5 6 7 8 二、算法选择: 本次实验采用了A*搜索算法来解决八数码问题。A*算法是一种启发式搜索算法,通过估计每个搜索节点到达目标状态的代价来进行搜索。它综合了广度优先搜 索和最佳优先搜索的优点,能够高效地找到最优解。 三、实验过程:

1. 状态表示: 在实验中,我们使用一个3x3的二维数组来表示八数码的状态。数组中的每个元素代表一个方格的数字,空白方格用0表示。 2. 启发函数: 为了评估每个搜索节点到达目标状态的代价,我们需要定义一个启发函数。本实验中,我们选择了曼哈顿距离作为启发函数。曼哈顿距离是指每个数字方格与其目标位置之间的水平和垂直距离之和。 3. A*算法: A*算法的核心思想是维护一个优先队列,根据每个搜索节点的估价函数值进行排序。具体步骤如下: - 将初始状态加入优先队列,并设置初始估价函数值为0。 - 从优先队列中取出估价函数值最小的节点,进行扩展。 - 对于每个扩展节点,计算其估价函数值,并将其加入优先队列。 - 重复上述步骤,直到找到目标状态或者队列为空。 四、实验结果: 经过实验,我们发现A*算法能够高效地解决八数码问题。对于初始状态为随机排列的八数码,A*算法能够在较短的时间内找到最优解。实验结果表明,A*算法在解决八数码问题上具有较好的性能。 五、实验总结: 本次实验通过使用A*搜索算法解决八数码问题,展示了人工智能在解决复杂问题上的应用。A*算法通过合理的启发函数和优先队列的维护,能够高效地找到最优解。然而,A*算法也存在一些限制,例如对于状态空间较大的问题,搜索

人工智能大作业八数码问题

基于A星算法的八数码问题求解 学号:姓名: 摘要:在人工智能领域中, 八数码问题一直都是一个游戏难题。介绍了八数码问题, 然后在启发式搜索算法上对A * 算法定义进行了解释, 并在其旨在提高搜索效率的方面作了比较详尽的介绍, 详细描述了基于图搜索算法的解决此类问题的一种启发式搜索算法:A* 算法。再依据这种算法用可视化编程语言VC+ + 6. 0 来实现八数码问题的求解过程, 取得了预期的搜索解, 提高了搜索效率。 关键词:八数码问题; 启发式搜索; A* 算法 本组成员: 本人分工:主要负责进行问题分析,提出解决方案,进行系统设计,算法上具体负责主函数的编写。 1 引言 八数码问题是人工智能的一个经典的问题。文中通过设计一个基于A* 算法的状态空间搜索程序, 对于给定的初始状态, 采用h ( n ) = p ( n ) 表示以每一个将牌与目标位置之间距离的总和作为启发函数的度量, 并用可视化编程语言VC+ + 来实现该问题。 2 算法原理与系统设计 1)A*算法思想 A*算法是对A算法的估价函数f(n)=g(n)+h(n)加上某些限制后得到的一种启发式搜索算法。A*算法对A算法中的g(n)和h(n)分别提出如下限制:第一,g(n)是对最小代价g*(n)的估计,且g(n)>0;第二,h(n)是最小代价h*(n)的下界,即对任意节点n 均有h(n)≤h*(n)。即满足上述两条限制的A算法称为A*算法。 2)估价函数 用来估算节点希望程度的量度,叫估价函数f(x),f(x)=g(x)+h(x)。g(x)为从初始节点到当前节点已经付出的代价,h(x)为从当前节点到目标节点的最优路径的估计代价。本算法中令g(x)为当前节点的深度depth,h(x)为当前节点每个数字位与目标节点数字位间距离和dist,进一步考虑当前结点与目标结点的距离信息,令启发函数h ( n )为当前8个数字位与目标结点对应数字位距离和(不考虑中

用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 ) 满足单调限制条件。 2算法介绍 A*算法的一般介绍 A*(A-Star)算法是一种静态路网中求解最短路最有

武汉理工大学人功智能概论八数码实验报告

武汉理工大学 学生实验报告书 实验课程名称人工智能概论B 实验名称八数码问题 开课学院计算机科学与技术学院 指导老师姓名 学生姓名 学号 学生专业班级 2016 —2017 学年第一学期

一、实验要求及问题描述 采取分组形式,2人一组,一人使用盲目搜索中的宽度优先搜索算法,另一人使用启发式搜索中的全局择优搜索或A*算法。每组提交一份大作业报告,该报告包括设计、实现、测试、实验对比结果分析、结论、个人体会与总结。提交截止时间:2016.11.18 对任意的八数码问题,给出求解结果。例如:对于如下具体八数码问题: ⇨ 通过设计启发函数,编程实现求解过程,如果问题有解,给出数码移动过程,否则,报告问题无解。 250 123 873 804 641 765 二、实验原理 2.1 状态空间表示 1、建立只有初始节点S 0的搜索图,并将S 放入OPEN表中; 2、建立CLOSE表并置空; 3、对OPEN表进行判断,若OPEN表为空,则无解; 4、将OPEN表中的第一个节点移出,放入CLOSE表中,记为节点n; 5、判断节点n是否为目标节点。是,则有解,解为沿n到S 的路径,否,则进行步骤6; 6、由节点n生成一组不是n的祖先的后继节点,记为集合P,将P中节点作为n的后继加入搜索图; 7、对于在OPEN表和CLOSE表中没有出现过的集合P中的节点,设置指向节点n的指针,把这些节点放入OPEN表中;对于在OPEN表和CLOSE表中已经出现过的P中的节点,确定是否修改指向父节点的指针; 8、重拍OPEN表节点顺序; 9、转到步骤3。 2.2 数据结构设计 //宽度优先搜索中,八数码地图节点结构体

八数码问题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)。第二点特别的重要。可以证明应用这样的估价函数是可以找到最短路径的。 *算法的步骤 A*算法基本上与广度优先算法相同,但是在扩展出一个结点后,要计算它的估价函数,并根据估价函数对待扩展的结点排序,从而保证每次扩展的结点都是估价函数最小的结点。 A*算法的步骤如下: 1)建立一个队列,计算初始结点的估价函数f,并将初始结点入队,设置队列头和尾指针。 2)取出队列头(队列头指针所指)的结点,如果该结点是目标结点,则输出路径,程序结束。否则对结点进行扩展。 3)检查扩展出的新结点是否与队列中的结点重复,若与不能再扩展的结点重复(位于队列头指针之前),则将它抛弃;若新结点与待扩展的结点重复(位于队列头指针之后),则比较两个结点的估价函数中g的大小,保留较小g值的结点。

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

实验一 启发式搜索算法 姓名:徐维坚 学号:2220103484 日期:2012/6/29 一、实验目的: 熟练掌握启发式搜索A *算法及其可采纳性。 二、实验内容: 使用启发式搜索算法求解8数码问题。 1) 编制程序实现求解8数码问题A *算法,采用估价函数 ()()()() w n f n d n p n ⎧⎪=+⎨⎪⎩, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数;()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。 2) 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是()p n 的上界 的()h n 的定义,并测试使用该估价函数是否使算法失去可采纳性。 三、实验原理: 1. 问题描述: 八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格(以数字0来表示),与空格相邻的棋子可以移到空格中。 要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。 所谓问题的一个状态就是棋子在棋盘上的一种摆法。解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。 2. 原理描述: 2.1 有序搜索算法: (1)原理: 在搜索过程中,OPEN 表中节点按照其估价函数值以递增顺序排列,选择OPEN 表中具有最小估价函数值的节点作为下一个待扩展的节点,这种搜索方法称为有序搜索。 在本例中,估价函数中的)(n g 取节点深度)(n d ,)(n h 为节点n 的状态与目标状态之间错放的个数,即函数)(n ω。

西电八数码问题求解

西安电子科技大学课程论文数据结构 八数码问题的求解 班级: 作者: 学号: 时间:

摘要 八数码问题也称为九宫问题,在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格(以0标记),与空格相邻的棋子可以移到空格中。给定初始位置和目标位置,要求通过一系列的数码移动,将初始状态转化为目标状态。状态转换的规则:空格四周的数移向空格,我们可以看作是空格移动,它最多可以有4个方向的移动,即上、下、左、右。九宫重排问题的求解方法,就是从给定的初始状态出发,不断地空格上下左右的数码移至空格,将一个状态转化成其它状态,直到产生目标状态。一般用搜索法来解决:广度优先搜索法、深度优先搜索法、A*算法等,本文用全局择优来解决该问题。 引言 八数码问题是人工智能中一个很典型的智力问题。一般用搜索法来解决:广度优先搜索法、深度优先搜索法、A*算法等。搜索就是按照一定规则扩展已知结点,直到找到目标结点或所有结点都不能扩展为止,广度优先是从初始状态一层一层向下找,直到找到目标为止。深度优先是按照一定的顺序前查找完一个分支,再查找另一个分支,以至找到目标为止。广度和深度优先搜索有一个很大的缺陷就是他们都是在一个给定的状态空间中穷举。由于八数码问题状态空间共有9!个状态,对于八数码问题如果选定了初始状态和目标状态,有9!/2个状态要搜索,考虑到时间和空间的限制,在这里采用A*算法作为搜索策略。A*是一种静态路网中求解最短路径最有效的方法,公式表示为:f(n)=g(n)+h(n),其中f(n) 是从初始点经由节点n到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n) 是从n到目标节点最佳路径的估计代价,保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取。 一、需求分析 ①八数码游戏(八数码问题)描述为:在3×3组成的九宫格棋盘上,摆有八

八数码实验报告

八数码实验报告 利用人工智能技术解决八数码游戏问题 1.八数码游戏问题简介 九宫排字问题(又称八数码问题)是人工智能当中有名的难题之一。问题是在3×3方格盘上,放有八个数码,剩下第九个为空,每一空格其上下左右的数码可移至空格。问题给定初始位置和目标位置,要求通过一系列的数码移动,将初始位置转化为目标位置。 2.八数码游戏问题的状态空间法表示 ①建立一个只含有初始节点s0的搜索图g,把s0放入open表中 ②建立closed表,且置为空表 ③判断open表是否为空表,若为空,则问题无解,退出 ④选择open表中的第一个节点,把它从open表移出,并放入closed表中,将此节点记为节点n ⑤考察节点n是否为目标节点,若是,则问题有解,成功退出。问题的解就是沿着n到s0的路径得到。若不是转⑥ ⑥扩展节点n生成一组不是n的祖先的后继节点,并将它们记为集合m,将m中的这些节点作为n的后继节点加入图g中 ⑦对未在g中出现过的(open和closed表中未出现过的)集合m中的节点, 设置一个指向父节点n的指针,并把这些节点放入open 表中;对于已在g中出现过的m中的节点,确定是否需要修改指向父节点的指针;对于已在g中出现过并已在closed表中的m中的节点,确定是否需要修改通向他们后继节点的指针。 ⑧按某一任意方式或某种策略重排open表中节点的顺序 ⑨转③ 3.八数码游戏问题的盲目搜索技术 宽度优先搜索: 1、定义 如果搜索是以接近起始节点的程度依次扩展节点的,那么这种搜索就叫做宽度优先搜索(breadth-first search)。

2、特点 这种搜索是逐层进行的;在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点。 3、宽度优先搜索算法 (1) 把起始节点放到open表中(如果该起始节点为一目标节点,则求得一个解答)。 (2) 如果open是个空表,则没有解,失败退出;否则继续。 (3) 把第一个节点(节点n)从open表移出,并把它放入closed的扩展节点表中。 (4) 扩展节点n。如果没有后继节点,则转向上述第(2)步。 (5) 把n的所有后继节点放到open表末端,并提供从这些后继节点回到n的指针。 (6) 如果n的任一个后继节点是个目标节点,则找到一个解答,成功退出;否则转向第(2)步。 流程图: 性质: 当问题有解时,一定能找到解。 当问题为单位消耗值,且问题有解时,一定能找到最优解。 算法与问题无关,具有通用性。 时间效率和空间效率都比较低。 深度优先搜索: 1、定义 在此搜索中,首先扩展最新产生的(即最深的)节点。深度相等的节点可以任意排列。这 种盲目(无信息)搜索叫做深度优先搜索(depth-first search)。 2、特点 首先,扩展最深的节点的结果使得搜索沿着状态空间某条单一的路径从起始节点向下进 行下去;只有当搜索到达一个没有后裔的状态时,它才考虑另一条替代的路径。

八数码问题求解西安电子科技大学数据结构结课大作业

西安电子科技大学课程论文数据结构八数码问题求解 班级:071271 作者:方正阳

学号:07127020 时间:2013.12.17 摘要:八数码求解问题是人工智能中一个很典型的智力问题。本文套用经典宽度搜索框架来讨论八数码问题,给出了宽度优先搜索算法与实现的思想。用链表法来表示邻接点的访问序列,从而完成对图的遍历。根据宽度优先搜索的策略,被搜索到的顶点上的distance标记就是到源顶点的最短路径的距离,因此可以解决无权图的最短路径问题以及由其抽象而来的最优问题。 引言:八数码游戏(八数码问题)描述为:在3×3方格盘上,放有八个数码,剩下一个位置为空,每一空格其上下左右的数码可移至空格(可以看作是空格移动,它最多可以有4个方向的移动,即上、下、左、右),这样通过移动将牌就可以不断改变将牌的布局。这种游戏求解的问题是:给定一种初始的将牌布局或结构(称初始状态)和一个目标的布局(称目标状态),问如何移动将牌,实现从初始状态到目标状态的转变。 一、需求分析 初始状态:8个数字码和空格在3×3棋盘上的所有格局组成了问题的状态空间。其中,状态空间中的任一种状态都可以作为初始状态。 后继状态:通过移动空格(上、下、左、右)和周围的任一棋子一次,到达新的合法状态。

目标测试:比较当前状态和目标状态的格局是否一致。 路径消耗:每一步的耗散值为1,因此整个路径的耗散值是从起始状态到目标状态的棋子移动的总步数。 具体要求:1.输入初始状态和目标状态的数据; 例:初始状态:2 8 3 1 6 4 7 0 5 最终状态:1 2 3 8 0 4 7 6 5 2.实现从初始状态到目标状态的转换(如不能实现,程序应输出不能实现的提示 信息); 3.输出结果,每移动一步都必须在屏幕上显示: a、移动每一步时的序号,最后一步的序号即为移动总步数; b、每一步移动后以3x3表格形式显示状态。 4.要求能使移动步数尽可能少; 二、程序设计 1.变量说明: int num[9]; //棋盘状态int deepth; //派生的深度g(n) int diffnum; //不在位的数目h(n) int value; //耗散值f(n)=g(n)+h(n) int expand(numNode *item); //扩展节点 int chu_shi_zhuang_tai[9]; //棋盘初始状态 int mu_biao_zhuang_tai[9]; //棋盘目标状态 int numNode_num,total_step; numNode *open,*close; //Open表和Close表 2.函数声明: void print_num(int num[9]); //打印棋盘状态

相关主题
相关文档
最新文档