八数码问题: 八数码的游戏 九宫格里面放入8个数字 启发式搜索(1)
2016-09-23 00:55
555 查看
八数码问题:
我想大家小时候一定玩过八数码的游戏,如下图:在一个九宫格里面放入8个数字,数字只能上下左右移动,并且只能移动到空白处。通过若干此移动后,能把数字移动成图1.1右方所示图案。
图1.1(左边为开始格局,右边为移动后最终格局)
下图是图1.1下一个格局的三种情况:
图1.2
如果按正常的思维,采用盲目搜索的话,不仅搜索的次数多,而且往往容易陷入死循环中,所以面对此问题需要一种策略——启发式搜索
启发式搜索:启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无谓的搜索路径,提高了效率
解决此问题的启发策略:
每次移动的时候,正确位置数码的个数要大于交换前正确位置数码个数。
正确位置数码个数:每个数码的位置与最终格局的对比,如果位置相同,则说明此数码在正确位置。
如下图:
图1.3
图1.3中右边为最终格局,左边为当前格局,红色字体标识的数码为 正确位置数码,由此可以发现其正确位置的数码个数为4个。那么图1.2中正确数码如下图所示:
由上图所示可得,正确位置数码个数大于等于4的只有左下方的格局,那么下一步选择的就是左下方的格局,再次调用次算法如下图:
这样一步步的最终即可得到最终格局
源代码:
[cpp] view plain copy
#include"stdio.h"
#define num 3 //宏定义数码的行列数为3
void show(int begin[num][num])
{
for(int i = 0; i < num; i++)
{
for(int j = 0; j < num; j++)
printf("%d ", begin[i][j]);
printf("\n");
}
printf("\n");
}
void exchange(int begin[num][num], int row_one, int column_one, int row_two, int column_two)
{
int temp;
temp = begin[row_two][column_two] ;
begin[row_two][column_two] = begin[row_one][column_one];
begin[row_one][column_one] = temp;
}
int judge(int begin[num][num], int end[num][num])
{
int count=0; //count记录数码中正确位置的个数
for(int i = 0; i < num; i++) //检查当前图形的正确度
for(int j = 0; j < num; j++)
{
if(begin[i][j] == end[i][j] && end[i][j] != 0)
count++;
}
return count; //返回数码中正确位置的个数
}
int yidong(int begin[num][num], int end[num][num]
, int right, int jishu, int ji_shu[50][3][3]
, int biaoji, int row, int column) //biaoji存储上一轮移动的反方向代号
{
int temp_zhi;
show(begin); //显示数组矩阵
if(jishu >= 20)
return 0;
int node; //,node为标记
int temp; //存储当前待调整数码正确的个数
for(int q=0; q//检查交换后的end[][]图形是否先前已经遍历过了
{
node = 1;
for(int w=0; w
for(int r=0; r
if(ji_shu[q][w][r] != begin[w][r])
node = 0;
if(node == 1) //如果先前遍历过,返回0
{
return 0;
}
}
for(int i = 0; i < num; i++)
for(int j = 0; j < num; j++)
ji_shu[jishu][i][j] = begin[i][j];
if(right == num * num - 1) //如果待调整数码与最终数码完全相同时,返回1
return 1;
if(row > 0 && biaoji != 0) //存储0的位置不是在第一行
{
exchange(begin, row - 1, column, row , column); //将0与其上面的元素交换存储位置
temp = judge(begin, end);
if(temp < right) //如果交换后正确数码的个数不大于原来正确数码的个数
exchange(begin, row - 1, column, row , column); //再将其交换回来
else if(temp >= right) //如果交换后正确数码的个数大于或等于原来正确数码的个数
{
temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu, 2, row-1, column);
if( temp_zhi == 1) //进行下一步的移动
return 1;
exchange(begin, row - 1, column, row , column); //再将其交换回来
}
}
if(column > 0 && biaoji != 1)
{
exchange(begin, row, column - 1, row , column); //将0与其左边的元素交换存储位置
temp = judge(begin, end);
if(temp < right)
exchange(begin, row, column - 1, row , column);
else if(temp >= right)
{
temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu ,3, row, column - 1);
if(temp_zhi == 1)
return 1;
exchange(begin, row, column - 1, row , column);
}
}
if(row < num-1 && biaoji != 2)
{
exchange(begin, row + 1, column, row , column); //将0与其下面的元素交换存储位置
temp = judge(begin, end);
if(temp < right)
exchange(begin, row + 1, column, row , column);
else if(temp >= right)
{
temp_zhi =yidong(begin, end, temp, jishu+1, ji_shu, 0, row+1, column);
if(temp_zhi == 1)
return 1;
exchange(begin, row + 1, column, row , column);
}
}
if(column < num-1 && biaoji != 3)
{
exchange(begin, row, column + 1, row , column); //将0与其右边的元素交换存储位置
temp = judge(begin, end);
if(temp < right)
exchange(begin, row, column + 1, row , column);
else if(temp >= right)
{
temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu, 1, row, column+1);
if(temp_zhi == 1)
return 1;
exchange(begin, row, column + 1, row , column);
}
}
return 0; //移动失败,返回0
}
void shuru(int begin[][num],int blank[])
{
int temp, node, zero = 0;
for (int i = 0; i < num; i++)
for(int j = 0; j < num; j++)
{
node = 1;
printf("请输入第%d行,第%d列的元素的值:", i+1, j+1);
scanf("%d", &temp);
for (int q = 0; q <= i && node == 1; q++) //当输入的值有重复的,提示重新输入
for (int w = 0; w < j; w++)
if(temp == begin[q][w])
{
printf("输入重复,请重新输入\n");
node = 0;
j--;
break;
}
if(temp < 0 || temp > num*num-1) //当输入的值不是在数码的区间范围内时,提示重新输入
{
printf("请输入从%d到%d的数\n", zero, num*num-1);
node = 0;
j--;
}
if(node == 1) //如果输入满足条件
{
if(temp == 0) //如果输入的值为零,由blank[0]记录行号,blank[1]记录列号
{
blank[0] = i;
blank[1] = j;
}
begin[i][j] = temp;//将满足条件的值存储起来
}
}
}
int main()
{
int jishu = 0, ji_shu[50][3][3];//jishu存储已经遍历过的八数码图形的个数,jishu[][][]存储已经遍历过的八数码图形的形状
int row; //存储数字零的行数
int column; //存储数字零的列数
int begin[num][num], blank[2],count=1;
int end[num][num] = {1, 2, 3, 8, 0, 4, 7, 6, 5}; //给最终状态的数码矩阵赋值
printf ("-------%d数码游戏开始!--------\n", num);
shuru(begin, blank); //输入带调整状态的数码矩阵的值
row = blank[0];
column = blank[1];
if(yidong (begin, end,judge(begin,end),jishu,ji_shu,4,row,column) == 0)
printf("\n此8数码的问题可能无解!");
else
show(begin);
getchar();getchar();
return 0;
}
总结:此算法运用了启发式搜索策略,根据正确位置数码个数选择下一步移动方案。虽然此算法能够解决八数码问题,但是移动的次数不是最少,因而再次算法上升级
转自:http://blog.csdn.net/q345852047/article/details/6626684
我想大家小时候一定玩过八数码的游戏,如下图:在一个九宫格里面放入8个数字,数字只能上下左右移动,并且只能移动到空白处。通过若干此移动后,能把数字移动成图1.1右方所示图案。
图1.1(左边为开始格局,右边为移动后最终格局)
下图是图1.1下一个格局的三种情况:
图1.2
如果按正常的思维,采用盲目搜索的话,不仅搜索的次数多,而且往往容易陷入死循环中,所以面对此问题需要一种策略——启发式搜索
启发式搜索:启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无谓的搜索路径,提高了效率
解决此问题的启发策略:
每次移动的时候,正确位置数码的个数要大于交换前正确位置数码个数。
正确位置数码个数:每个数码的位置与最终格局的对比,如果位置相同,则说明此数码在正确位置。
如下图:
图1.3
图1.3中右边为最终格局,左边为当前格局,红色字体标识的数码为 正确位置数码,由此可以发现其正确位置的数码个数为4个。那么图1.2中正确数码如下图所示:
由上图所示可得,正确位置数码个数大于等于4的只有左下方的格局,那么下一步选择的就是左下方的格局,再次调用次算法如下图:
这样一步步的最终即可得到最终格局
源代码:
[cpp] view plain copy
#include"stdio.h"
#define num 3 //宏定义数码的行列数为3
void show(int begin[num][num])
{
for(int i = 0; i < num; i++)
{
for(int j = 0; j < num; j++)
printf("%d ", begin[i][j]);
printf("\n");
}
printf("\n");
}
void exchange(int begin[num][num], int row_one, int column_one, int row_two, int column_two)
{
int temp;
temp = begin[row_two][column_two] ;
begin[row_two][column_two] = begin[row_one][column_one];
begin[row_one][column_one] = temp;
}
int judge(int begin[num][num], int end[num][num])
{
int count=0; //count记录数码中正确位置的个数
for(int i = 0; i < num; i++) //检查当前图形的正确度
for(int j = 0; j < num; j++)
{
if(begin[i][j] == end[i][j] && end[i][j] != 0)
count++;
}
return count; //返回数码中正确位置的个数
}
int yidong(int begin[num][num], int end[num][num]
, int right, int jishu, int ji_shu[50][3][3]
, int biaoji, int row, int column) //biaoji存储上一轮移动的反方向代号
{
int temp_zhi;
show(begin); //显示数组矩阵
if(jishu >= 20)
return 0;
int node; //,node为标记
int temp; //存储当前待调整数码正确的个数
for(int q=0; q//检查交换后的end[][]图形是否先前已经遍历过了
{
node = 1;
for(int w=0; w
for(int r=0; r
if(ji_shu[q][w][r] != begin[w][r])
node = 0;
if(node == 1) //如果先前遍历过,返回0
{
return 0;
}
}
for(int i = 0; i < num; i++)
for(int j = 0; j < num; j++)
ji_shu[jishu][i][j] = begin[i][j];
if(right == num * num - 1) //如果待调整数码与最终数码完全相同时,返回1
return 1;
if(row > 0 && biaoji != 0) //存储0的位置不是在第一行
{
exchange(begin, row - 1, column, row , column); //将0与其上面的元素交换存储位置
temp = judge(begin, end);
if(temp < right) //如果交换后正确数码的个数不大于原来正确数码的个数
exchange(begin, row - 1, column, row , column); //再将其交换回来
else if(temp >= right) //如果交换后正确数码的个数大于或等于原来正确数码的个数
{
temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu, 2, row-1, column);
if( temp_zhi == 1) //进行下一步的移动
return 1;
exchange(begin, row - 1, column, row , column); //再将其交换回来
}
}
if(column > 0 && biaoji != 1)
{
exchange(begin, row, column - 1, row , column); //将0与其左边的元素交换存储位置
temp = judge(begin, end);
if(temp < right)
exchange(begin, row, column - 1, row , column);
else if(temp >= right)
{
temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu ,3, row, column - 1);
if(temp_zhi == 1)
return 1;
exchange(begin, row, column - 1, row , column);
}
}
if(row < num-1 && biaoji != 2)
{
exchange(begin, row + 1, column, row , column); //将0与其下面的元素交换存储位置
temp = judge(begin, end);
if(temp < right)
exchange(begin, row + 1, column, row , column);
else if(temp >= right)
{
temp_zhi =yidong(begin, end, temp, jishu+1, ji_shu, 0, row+1, column);
if(temp_zhi == 1)
return 1;
exchange(begin, row + 1, column, row , column);
}
}
if(column < num-1 && biaoji != 3)
{
exchange(begin, row, column + 1, row , column); //将0与其右边的元素交换存储位置
temp = judge(begin, end);
if(temp < right)
exchange(begin, row, column + 1, row , column);
else if(temp >= right)
{
temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu, 1, row, column+1);
if(temp_zhi == 1)
return 1;
exchange(begin, row, column + 1, row , column);
}
}
return 0; //移动失败,返回0
}
void shuru(int begin[][num],int blank[])
{
int temp, node, zero = 0;
for (int i = 0; i < num; i++)
for(int j = 0; j < num; j++)
{
node = 1;
printf("请输入第%d行,第%d列的元素的值:", i+1, j+1);
scanf("%d", &temp);
for (int q = 0; q <= i && node == 1; q++) //当输入的值有重复的,提示重新输入
for (int w = 0; w < j; w++)
if(temp == begin[q][w])
{
printf("输入重复,请重新输入\n");
node = 0;
j--;
break;
}
if(temp < 0 || temp > num*num-1) //当输入的值不是在数码的区间范围内时,提示重新输入
{
printf("请输入从%d到%d的数\n", zero, num*num-1);
node = 0;
j--;
}
if(node == 1) //如果输入满足条件
{
if(temp == 0) //如果输入的值为零,由blank[0]记录行号,blank[1]记录列号
{
blank[0] = i;
blank[1] = j;
}
begin[i][j] = temp;//将满足条件的值存储起来
}
}
}
int main()
{
int jishu = 0, ji_shu[50][3][3];//jishu存储已经遍历过的八数码图形的个数,jishu[][][]存储已经遍历过的八数码图形的形状
int row; //存储数字零的行数
int column; //存储数字零的列数
int begin[num][num], blank[2],count=1;
int end[num][num] = {1, 2, 3, 8, 0, 4, 7, 6, 5}; //给最终状态的数码矩阵赋值
printf ("-------%d数码游戏开始!--------\n", num);
shuru(begin, blank); //输入带调整状态的数码矩阵的值
row = blank[0];
column = blank[1];
if(yidong (begin, end,judge(begin,end),jishu,ji_shu,4,row,column) == 0)
printf("\n此8数码的问题可能无解!");
else
show(begin);
getchar();getchar();
return 0;
}
总结:此算法运用了启发式搜索策略,根据正确位置数码个数选择下一步移动方案。虽然此算法能够解决八数码问题,但是移动的次数不是最少,因而再次算法上升级
转自:http://blog.csdn.net/q345852047/article/details/6626684
相关文章推荐
- 启发式搜索程序设计-八数码问题
- visual studio 2008 运行DirectX 9.0 游戏开发编程基础里面的源码的问题
- Problem 2089 数字游戏 大数问题
- 关于游戏里面装备有概率掉落、套装收集问题的matlab模拟编程
- 如何排除猜数游戏中输入非数字的问题?
- 八数码问题(启发式搜索)
- js里面字符1和数字1相加的结果是11,如何解决这个问题。js里面使用EL表达式。
- 吴昊品游戏核心算法 Round 17 ——(转载)八数码问题的十重境界
- ACM之八数码问题----BFS搜索----数独游戏的模拟(下)
- 解决table td里面长串数字或字母不换行的问题
- 启发式搜索-A*算法解决八数码问题
- 取a数组里面的8个数字!让他们结果相加等于1979970
- 数字拼图问题(八数码)求解过程动态演示
- 启发式搜索解决8数码问题
- 问题描述如下: 有2.5亿个整数(这2.5亿个整数存储在一个数组里面,至于数组是放在外存还是内存,没有进一步具体说明); 要求找出这2.5亿个数字里面,不重复的数字的个数; 另外,可用的内存限定为600M; 要求算法尽量高效,最优;
- java基础问题----------TreeSet里面放对象,如果同时放入了父类和子类的实例对象
- List的排序。在一个list里面放入"1","2"..."10","11"...,"99999","100000",使用字符串大小的顺序与解析成的数字的大小进行排序
- ACM之八数码问题----BFS搜索----数独游戏的模拟(中)
- 【启发式搜索】八数码问题