【问题标题】:Using recursion in DFS to solve a logic game using C?在 DFS 中使用递归来解决使用 C 的逻辑游戏?
【发布时间】:2015-10-16 20:47:35
【问题描述】:

我有以下问题:这个游戏的目标是从棋盘上移除除一个之外的所有钉子。完美的游戏只在中心位置留下一个钉子(黑色的)。基本上,通过用另一个钉子跳过每个钉子来移除钉子。只有在钉子的另一边有空位并且我就在钉子前面时,我才能跳过钉子。

我正在尝试理解以下递归函数,该函数试图使用深度优先搜索来解决问题。虽然我有点熟悉这个问题在正常情况下是如何工作的,这意味着当我需要移除钉子时。当我最终处于无法消除挂钩的情况下,我无法很好地掌握递归步骤,在接下来的步骤中,我不得不提出旧的消除挂钩(回溯),以便我会发现解决方案的另一条途径。这似乎消耗了大量的执行时间。

函数的一般流程是:

  1. 使用嵌套的 for 循环遍历电路板。
  2. 如果满足以下条件,则找到要移动的钉子:
  3. 在左上或右下有一个直接相邻的。
  4. 卸下要卸下的挂钩后,有一个空闲的地方可以移动。
  5. 如果所有这些条件都为真,我们将更改挂钩的状态
  6. 如果无法再移动钉子,请恢复之前的电路板配置并寻找其他路径。

这里是预处理器指令:

#include <stdio.h>
#define N 11
/****** Accepted or unaccepted solution ******/
#define YES 1
#define NO 0

/****** Representation of the board ******/
/* 0 - the position is free: no peg is in the position
   1 - a peg is in the postion
   2 - an obstacle is in the position (not part of the board) */  

#define OCCUPIED 1
#define FREE 0
#define WALL 2

/****** Stack size ******/
#define MAXST 5000

typedef char boolean;
/****** Directions where to move *****/
enum dir{NORTH,EAST,SOUTH,WEST};
/****** Directions horizentally ******/
int dx[]={0, 1,0,-1};
/****** Directions Vertically ******/
int dy[]={-1,0,1, 0};

/****** Board Representation ******/
char b[N][N]={
{2, 2,2,2,2,2,2,2,2,2, 2},

{2, 2,2,2,1,0,0,2,2,2, 2},
{2, 2,2,2,0,0,1,2,2,2, 2},
{2, 2,2,2,0,0,0,2,2,2, 2},
{2, 0,0,1,0,0,0,1,1,1, 2},
{2, 0,0,0,0,0,0,0,0,0, 2},
{2, 0,1,0,0,1,0,0,0,0, 2},
{2, 2,2,2,1,0,0,2,2,2, 2},
{2, 2,2,2,0,0,0,2,2,2, 2},
{2, 2,2,2,1,0,0,2,2,2, 2},

{2, 2,2,2,2,2,2,2,2,2, 2}
};

这是负责寻找解决方案的函数:

    /****** move finds the next move to perform in order to advance in the search ******/
    boolean move(int pegs){
    /****** x - the x position of the peg examined on the board
            y - the y position of the peg examined on the board
            xnear - the x position of the adjascent peg to be removed
            ynear - the y position of the adjascent peg to be removed
            xnew - the new x position of the peg that expelled the removed previous peg
            ynew - the new x position of the peg that expelled the removed previous peg ****/
    int x,y,xnear,ynear,xnew,ynew;

    enum dir d;

    /* Base case 1: solution = one peg left on the whole board */

    /* if(pegs==1){
        return(YES);
    } */

    /* Base case 2: solution = one peg at the center of the board (5,5) */
        if(pegs==1) {
            if (b[5][5]==OCCUPIED)
                return(YES);
            else return(NO);
        }
        /*Scanning the board from top to bottom, left to right*/
        for(x=0;x<N;x++)
            for(y=0;y<N;y++)
            /* In order for the move to occur you need to 1. have a peg in a position */
                if(b[y][x] == OCCUPIED){
                    /**************/
                    /* Finding adjascent pegs to remove from the board */ 
                    for(d=NORTH;d<=WEST;d++){
                        xnear=x+dx[d];
                        ynear=y+dy[d];
                        /*****************/
                        /* 2. Have another peg adjascent to the peg making the move */
                        if(b[ynear][xnear]== OCCUPIED){
                            xnew=xnear+dx[d];
                            ynew=ynear+dy[d];
                            /****************/
                            /* 3. Have the position where the peg will be moving empty */
                            if(b[ynew][xnew]==FREE){
                                b[y][x]=FREE; /* do move */
                                b[ynear][xnear]=FREE;   
                                b[ynew][xnew]=OCCUPIED;
                                pegs--;
                                print_board(b);
                                push(b,x,y,d); // Pushing the action to a stack
                                if(move(pegs)){
                                    return(YES);
                                }

                                b[y][x]=OCCUPIED; /* undo move */
                                b[ynear][xnear]=OCCUPIED;
                                b[ynew][xnew]=FREE;

                                pegs++;
                                pop(); 
                            }
                        }
                    }
                }
            return(NO);
        }

我的问题是:

  1. boolean move(int pegs) 函数的递归部分如何在代码中工作,它如何跟踪已经扩展的导致死胡同的案例? 我的猜测是在 boolean move(int pegs) 函数中,并且准确地说:

            if(move(pegs)){
                 return(YES);
            }
            b[y][x]=OCCUPIED; /* undo move */
            b[ynear][xnear]=OCCUPIED;
            b[ynew][xnew]=FREE;
            print_board(b);
            pegs++;
            pop();   
    
  2. 执行时间过长才能找到解决方案(很多小时但仍未找到解决方案)是否正常?有没有办法提高执行时间?

【问题讨论】:

    标签: c search recursion artificial-intelligence depth-first-search


    【解决方案1】:

    将会产生很多状态。 最初,有四种可能的移动。这些动作中的每一个都会导致几个可能的动作,依此类推。当您使用回溯时,您必须实际存储这些状态空间。

    您可以将此搜索视为一棵以根为初始状态的树。 (所以,初始状态会生成四个孩子......等等!)

    使用回溯时

    每当到达死胡同时,应该有一个布尔函数来确定是否可以移动,如果没有任何移动可能,我们会转到到达死胡同的父级并尝试父母的其他孩子。

    我们继续执行上述程序,直到找到解决方案。

    【讨论】:

      猜你喜欢
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-01
      • 1970-01-01
      • 2017-07-13
      相关资源
      最近更新 更多