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库试一下;

  • 相关阅读:
    ThreadSafety with the AutoResetEvent, ManualResetEvent Class(Synchronization of .net)
    使用Python SMTP发送邮件
    flask项目中设置logo
    如何解决Bootstrap中分页不能居中的问题
    pip install mysql_python报错解决办法
    git上拉项目
    AttributeError: 'str' object has no attribute 'decode'
    pycharm设置SDK
    为git创建远程仓库
    开发过程中git的使用
  • 原文地址:https://www.cnblogs.com/dragonfive/p/2979529.html
Copyright © 2011-2022 走看看