zoukankan      html  css  js  c++  java
  • ACM之八数码问题BFS搜索数独游戏的模拟(上)

    题目描述;数独游戏的内核模拟
    八数码问题;
    编号为1到8的8个正方形滑块被摆成3行3列;(有一个格子留空);
    每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中;
    而它原来的位置就成为了新的空格;给定初始局面和目标局面(用0表示空格);
    你的任务死计算出最少的移动步数;和移动过程;如果无法到达目标局面,则输出-1;

    2 6 4
    1 3 7
      5 8
     2
     3  6
     4    2

     这个问题也是要分步骤实现的,自然也涉及到状态的问题,和我的前一篇博客一样,使用的是广度优先遍历

    这样可以找到最少的步数;众所周知的是BFS算法之于树和之于图是不太一样的,

    因为树一旦往下走便不必担心访问到已经访问过的结点,而图呢由于有环的存在,所以会回到之前访问过的状态;

    这样就需要我们写一个判断是否重复的方法,上一篇博客里面的情况比较简单,因为可以直接用状态做下标进行随机访问;

    这里的情况就不一样了;我们先用c语言的遍历来实现一下,代码如下;

    使用头文件string.h因为这里要用到memcmp和memcpy函数和memset;
    这两个函数比我们写的循环效率要高

    为什么数组选择这么大呢?排列数9!;

    这里我把所有的变量都声明成全局变量的,在c语言编程方面不是一个好的编程style;
    但是在ACM这种对数据量要求极大的,情况下,数组申请在全局变量比在栈中申请要好;
    另外也方便了函数之间数据的交互,不需要多写什么参数了,

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h
      4 #define MAX 1000000
      5 typedef struct Node
      6 {
      7     int state[9];//存放本状态各个位置的数码值;
      8     int fa;//记录父节点的下标;
      9     int deepth;
     10     int last_x;
     11     int last_y;
     12 
     13 }Node;
     14 Node q[MAX];//构成状态数组;
     15 typedef struct Vis
     16 {
     17     int sequeue[9];//记录9个数码的位置;
     18     int visited;
     19 
     20 }Vis;
    
     21 Vis vis[MAX];//判断是否访问过;
     22 int vis_cur=0;//记录vis数组的当前索引位置;
     23 const int dx[4]={-1,1,0,0};//左右上下;
     24 const int dy[4]={0,0,-1,1};
     25 //bool has_vis(const int * state_to_decide);
     26 int has_vis=0;
     27 int bfs();//广度优先找到目标状态;
     28 void print_path(int founded);//根据fa成员,通过递归技术实现状态依次输出;
     29 Node destination;//存储目标状态;
     30 int i,j,k;
     31 int main()
     32 {
     33     /*首先输入起始状态和目标状态*/
     34     memset(q,0,sizeof q);
     35     for(i=0;i<9;i++)
     36     {
     37         scanf("%d",&(q[0].state[i]));
     38     }
     39     for(i=0;i<9;i++)
     40     {
     41         scanf("%d",&destination.state[i]);
     42     }
     43         memset(vis,0,sizeof vis);
     44     
     45     /*然后进行搜索并输出*/
     46     int founded=bfs();
     47     if(founded)
     48         print_path(founded);
     49     else
     50         printf("-1\n");
     51     system("pause");
     52     return 0;
     53 }
     54 int bfs()
     55 {
     56     memcpy(vis[0].sequeue,q[0].state,sizeof q[0].state);
     57     int front=0,rear=1;//用来模拟队列的先进先出,达到广度优先的目的;
     58     vis[0].visited=1;//第一个结点访问;
     59     vis_cur++;
     60     while (front<rear)
     61     {
     62         Node &first=q[front];
     63         if (memcmp(first.state,destination.state,sizeof destination.state)==0)
     64         {//找到了目标状态;
     65             return front;
     66         }
     67         for(i=0;i<9;i++)
     68             if (!first.state[i])
     69             {//找到空格处;
     70                 break;
     71             }
     72 
     73         for(j=0;j<4;j++)
     74         {//向四个方向进行转换;
     75             Node &new_Node=q[rear];
     76             memcpy(new_Node.state,first.state,sizeof first.state);
     77             int new_x=i%3+1+dx[j];
     78             int new_y=i/3+1+dy[j];
     79             
     80             if (new_x>0&&new_y>0&&new_x<4&&new_y<4)
     81             {
     82                 //位置合法
     83                 new_Node.state[i]=new_Node.state[i+dx[j]+3*dy[j]];//空格位置;
     84                 new_Node.state[i+dx[j]+3*dy[j]]=0;//新的状态形成了;
     85                 has_vis=0;
     86                 for(k=0;k<vis_cur;k++)//这里不用i,j因为i,j是全局变量且本函数是在循环里面的;
     87                 {
     88                     if((memcmp(vis[k].sequeue,new_Node.state,sizeof vis[k].sequeue))==0)
     89                     {
     90                         has_vis=1;
     91                         break;
     92                     }
     93                 }
     94                 if(!has_vis)//没有被访问;
     95                 {
     96                     new_Node.fa=front;
     97                     new_Node.deepth=first.deepth+1;
     98                     new_Node.last_x=dx[j];
     99                     new_Node.last_y=dy[j];
    100                     memcpy(vis[vis_cur].sequeue,new_Node.state,sizeof new_Node.state);
    101                     vis[vis_cur].visited=1;
    102                     vis_cur++;
    103                     rear++;
    104                 }//if
    105                 
    106             }//if
    107         }//for
    108         front++;
    109         printf("%d %d\n",front,q[front].deepth);
    110     }//while
    111     return 0;
    112 }
    113 void print_path(int founded)
    114 {
    115     if(q[founded].fa!=founded)
    116     {
    117         print_path(q[founded].fa);
    118     }
    119     for(i=0;i<3;i++)
    120     {
    121         for(j=0;j<3;j++)
    122         {
    123             printf("%d ",q[founded].state[3*i+j]);
    124         }
    125         printf("\n");
    126     }
    127     printf("\n");
    128 }
    129 /*bool has_vis(const int * state_to_decide)
    130 {
    131     for(k=0;k<vis_cur;k++)//这里不用i,j因为i,j是全局变量且本函数是在循环里面的;
    132     {
    133         if(memcmp(vis[k].sequeue,state_to_decide,sizeof vis[k].sequeue)==0)
    134             return true;
    135     }
    136     return false;
    137 }*/

    最后如你所见,我们的这个程序读取输入之后似乎没什么反应,其实它还是在工作的,我也是等了30多分钟之后才看到了曙光;

    显然这种遍历判断是否访问过的想法不仅没有提高效率,反而增加了上万次的无辜操作;

    那么该怎么提高效率呢,在下一个博客里面,我会用c++的stl库试一下;

  • 相关阅读:
    HDU 1102 Constructing Roads
    HDU 1285 确定比赛名次。
    最小生成树 HDU 各种畅通工程的题,prim和kru的模板题
    HDU Jungle Roads 1301 最小生成树、
    并查集小结(转)
    HDU hdu 2094 产生冠军 拓扑排序 判定环
    模运算(转)
    拓扑排序(主要是确定环和加法) HDU 2647 Reward
    HDU 1372 Knight Moves 简单BFS
    用计算机模型浅析人与人之间沟通方式 (一)如何谈话
  • 原文地址:https://www.cnblogs.com/dragonfive/p/2979529.html
Copyright © 2011-2022 走看看