八数码问题: 八数码的游戏 九宫格里面放入8个数字 启发式搜索(1)

 八数码问题:

我想大家小时候一定玩过八数码的游戏,如下图:在一个九宫格里面放入8个数字,数字只能上下左右移动,并且只能移动到空白处。通过若干此移动后,能把数字移动成图1.1右方所示图案。

    图1.1(左边为开始格局,右边为移动后最终格局)

 

下图是图1.1下一个格局的三种情况:

                                                图1.2

 

如果按正常的思维,采用盲目搜索的话,不仅搜索的次数多,而且往往容易陷入死循环中,所以面对此问题需要一种策略——启发式搜索

启发式搜索:启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无谓的搜索路径,提高了效率

 

解决此问题的启发策略:

每次移动的时候,正确位置数码的个数要大于交换前正确位置数码个数。

正确位置数码个数:每个数码的位置与最终格局的对比,如果位置相同,则说明此数码在正确位置。

如下图:

图1.3

图1.3中右边为最终格局,左边为当前格局,红色字体标识的数码为 正确位置数码,由此可以发现其正确位置的数码个数为4个。那么图1.2中正确数码如下图所示:

 

 由上图所示可得,正确位置数码个数大于等于4的只有左下方的格局,那么下一步选择的就是左下方的格局,再次调用次算法如下图:

这样一步步的最终即可得到最终格局

源代码:

[cpp]  view plain  copy
  1.   
  2.   
  3. #include"stdio.h"  
  4. #define num //宏定义数码的行列数为3  
  5.   
  6.   
  7. void show(int begin[num][num])    
  8.  
  9.     for(int 0; num; i++)  
  10.      
  11.         for(int 0; num; j++)  
  12.             printf("%d "begin[i][j]);  
  13.         printf("\n");  
  14.      
  15.     printf("\n");  
  16.  
  17.   
  18.   
  19. void exchange(int begin[num][num], int row_one, int column_one, int row_two, int column_two)    
  20.  
  21.     int temp;  
  22.     temp begin[row_two][column_two]  
  23.     begin[row_two][column_two] begin[row_one][column_one];  
  24.     begin[row_one][column_one] temp;  
  25.  
  26.   
  27.   
  28. int judge(int begin[num][num], int end[num][num])   
  29.  
  30.     int count=0;           //count记录数码中正确位置的个数  
  31.     for(int 0; num; i++)   //检查当前图形的正确度  
  32.         for(int 0; num; j++)  
  33.          
  34.             if(begin[i][j] == end[i][j] && end[i][j] != 0)  
  35.                 count++;  
  36.          
  37.     return count;           //返回数码中正确位置的个数  
  38.  
  39.    
  40.   
  41. int yidong(int begin[num][num], int end[num][num]  
  42.            int right, int jishu, int ji_shu[50][3][3]  
  43.            int biaoji, int row, int column) //biaoji存储上一轮移动的反方向代号  
  44.   
  45.     int temp_zhi;  
  46.     show(begin);   //显示数组矩阵  
  47.     if(jishu >= 20)  
  48.         return 0;  
  49.     int node;  //,node为标记  
  50.     int temp;               //存储当前待调整数码正确的个数  
  51.     for(int q=0; q//检查交换后的end[][]图形是否先前已经遍历过了  
  52.      
  53.         node 1;  
  54.         for(int w=0; w
  55.             for(int r=0; r
  56.                 if(ji_shu[q][w][r] != begin[w][r])  
  57.                     node 0;  
  58.         if(node == 1)   //如果先前遍历过,返回0  
  59.          
  60.             return 0;  
  61.          
  62.      
  63.     for(int 0; num; i++)     
  64.         for(int 0; num; j++)  
  65.             ji_shu[jishu][i][j] begin[i][j];  
  66.       
  67.     if(right == num num 1)  //如果待调整数码与最终数码完全相同时,返回1  
  68.         return 1;  
  69.     if(row && biaoji != 0)             //存储0的位置不是在第一行  
  70.      
  71.         exchange(begin, row 1, column, row column);  //将0与其上面的元素交换存储位置  
  72.         temp judge(begin, end);  
  73.         if(temp right)   //如果交换后正确数码的个数不大于原来正确数码的个数  
  74.             exchange(begin, row 1, column, row column); //再将其交换回来         
  75.         else if(temp >= right)          //如果交换后正确数码的个数大于或等于原来正确数码的个数  
  76.          
  77.             temp_zhi yidong(begin, end, temp, jishu+1, ji_shu, 2, row-1, column);  
  78.             iftemp_zhi == 1)  //进行下一步的移动  
  79.                 return 1;  
  80.             exchange(begin, row 1, column, row column); //再将其交换回来  
  81.          
  82.      
  83.     if(column && biaoji != 1)  
  84.      
  85.         exchange(begin, row, column 1, row column); //将0与其左边的元素交换存储位置  
  86.         temp judge(begin, end);         
  87.         if(temp right)     
  88.            exchange(begin, row, column 1, row column);            
  89.         else if(temp >= right)  
  90.          
  91.             temp_zhi yidong(begin, end, temp, jishu+1, ji_shu ,3, row, column 1);  
  92.             if(temp_zhi == 1)    
  93.                  return 1;  
  94.             exchange(begin, row, column 1, row column);  
  95.          
  96.      
  97.   
  98.     if(row num-1 && biaoji != 2)  
  99.      
  100.         exchange(begin, row 1, column, row column); //将0与其下面的元素交换存储位置  
  101.         temp judge(begin, end);     
  102.         if(temp right)   
  103.             exchange(begin, row 1, column, row column);  
  104.         else if(temp >= right)  
  105.          
  106.             temp_zhi =yidong(begin, end, temp, jishu+1, ji_shu, 0, row+1, column);  
  107.            if(temp_zhi == 1)    
  108.               return 1;  
  109.            exchange(begin, row 1, column, row column);  
  110.          
  111.      
  112.     if(column num-1 && biaoji != 3)  
  113.      
  114.         exchange(begin, row, column 1, row column); //将0与其右边的元素交换存储位置  
  115.         temp judge(begin, end);     
  116.         if(temp right)     
  117.             exchange(begin, row, column 1, row column);       
  118.         else if(temp >= right)    
  119.          
  120.             temp_zhi yidong(begin, end, temp, jishu+1, ji_shu, 1, row, column+1);  
  121.             if(temp_zhi == 1)    
  122.                return 1;  
  123.             exchange(begin, row, column 1, row column);   
  124.          
  125.      
  126.     return 0;   //移动失败,返回0  
  127.  
  128.   
  129.   
  130. void shuru(int begin[][num],int blank[])    
  131.  
  132.     int temp, node, zero 0;  
  133.     for (int 0; num; i++)  
  134.         for(int 0; num; j++)  
  135.          
  136.             node 1;  
  137.             printf("请输入第%d行,第%d列的元素的值:"i+1, j+1);  
  138.             scanf("%d"&temp);  
  139.             for (int 0; <= && node == 1; q++)  //当输入的值有重复的,提示重新输入  
  140.                 for (int 0; j; w++)  
  141.                     if(temp == begin[q][w])  
  142.                      
  143.                         printf("输入重复,请重新输入\n");  
  144.                         node 0;  
  145.                         j--;  
  146.                         break 
  147.                      
  148.             if(temp || temp num*num-1)   //当输入的值不是在数码的区间范围内时,提示重新输入  
  149.              
  150.                 printf("请输入从%d到%d的数\n"zero, num*num-1);  
  151.                 node 0;  
  152.                 j--;  
  153.              
  154.             if(node == 1)   //如果输入满足条件    
  155.              
  156.                 if(temp == 0) //如果输入的值为零,由blank[0]记录行号,blank[1]记录列号  
  157.                  
  158.                     blank[0] i;  
  159.                     blank[1] j;  
  160.                  
  161.                 begin[i][j] temp;//将满足条件的值存储起来  
  162.              
  163.          
  164.  
  165.   
  166. int main()  
  167.  
  168.     int jishu 0, ji_shu[50][3][3];//jishu存储已经遍历过的八数码图形的个数,jishu[][][]存储已经遍历过的八数码图形的形状  
  169.     int row;     //存储数字零的行数  
  170.     int column;  //存储数字零的列数  
  171.     int begin[num][num], blank[2],count=1;    
  172.     int end[num][num] {1, 2, 3, 8, 0, 4, 7, 6, 5};  //给最终状态的数码矩阵赋值  
  173.     printf ("-------%d数码游戏开始!--------\n"num);  
  174.     shuru(begin, blank);   //输入带调整状态的数码矩阵的值  
  175.     row blank[0];  
  176.     column blank[1];  
  177.     if(yidong (begin, end,judge(begin,end),jishu,ji_shu,4,row,column) == 0)    
  178.        printf("\n此8数码的问题可能无解!");  
  179.     else   
  180.        show(begin);  
  181.     getchar();getchar();  
  182.     return 0;  
  183.  


 

总结:此算法运用了启发式搜索策略,根据正确位置数码个数选择下一步移动方案。虽然此算法能够解决八数码问题,但是移动的次数不是最少,因而再次算法上升级

转自:http://blog.csdn.net/q345852047/article/details/6626684

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值