迷宫问题的C语言求解

1 .Preface

/**

* There have been many data to introduce the algorithm. So I will try to simply explain it and explain the program in detail.

*/

/**

* Prerequisites:

*  1). a survival skill in CPP programing language.

*  2). a curious mind for maze problem.

*

*/

//Image this, you have maze, just as following:

/*

*

*     1  1  1  1  1  1  1  1  1  1

*-> 1  0  0  1  0  0  0  1  0  1

*     1  0  0  1  0  0  0  1  0  1

*     1  0  0  0  0  1  1  0  0  1

*     1  0  1  1  1  0  0  0  0  1

*     1  0  0  0  1  0  0  0  0  1

*     1  0  1  0  0  0  1  0  0  1

*     1  0  1  1  1  0  1  1  0  1

*     1  1  0  0  0  0  0  0  0  1  -->exit

*     1  1  1  1  1  1  1  1  1  1

*/

//the entrance is [1,1], and exit is [8,8].

//How could you find a valid way to get through this?

/*

* when  start with [1, 1] , we will arrive some special position, which provide us many paths .For example, if we reside in [1, 1], there have two paths for us, [ 2, 1] and [ 1, 2]. Those speical nodes connect each other and compose a complexity topology network.

*

*

* To solve this problem, we could do as following:

*  step 1: just go ahead as one pleases , but record all nodes which has arrived.

*  step 2: if arrive a dead end, that mean you was choose a wrong path. So you need to go back the same way, find the last node which you did a choice, and  step into another choice.

*  step 3: Then repeat step 1 untill arrive the exit.

*

*/

2.Source code

/**

* Now, check this source code. I divided this problem with three parts: a stack, a map, and a boy who provide solve solution. First, let us put that poor little boy into this maze.( brutally )

*/

2. 1 Tool--stack.h

/**

* To traverse the network totally, the little boy must ensure he can go back the same way. So he save all of nodes,which he has been arrived,into a stack. The feature of stack is

* first in, first out. That‘s what we lack.

*/

/**
*    For make this stack more useful, a class template is created.
*/
#ifndef STACK_H
#define STACK_H

typedef int    INDEX;

template < class ELEM>
class STACK{
        public:
                STACK( int capacity);    //capacity
                ~STACK( void);
                /*
            *    some basic operation function.
            */
                bool    pop( ELEM &item);
                bool    push( ELEM item);
                /*
            *    sometimes, we want to visit those elements in the stack simply, instead of
            *    pop them from stack.
            */
                bool reset_v( void);        //reset view point
                bool pop_v( ELEM &item);	//view stack

        private:
                /*
            *    the bottom of stack
            */
                ELEM    *base;
                /*
            *    the top of stack.
            */
                INDEX    top;
                /*
            *	the current position for pop
            */
                INDEX    cur;
                /*
            *    the current postion for visit stack
            */
                INDEX    v_cur;
};

#define STACK_MAX    1000

/**
*    This is just a simply stack, and even don't consider dynamic extension.
*/
template <class ELEM>
STACK<ELEM>::STACK(int capacity)
{
        if( ( capacity<=0)
            ||( capacity>STACK_MAX))
        {
                this->base = NULL;
                return ;
        }
        this->base = NULL;
        this->base = new ELEM[capacity];
        this->top = capacity -1;
        this->cur = -1;
        this->v_cur = -1;
}

template <class ELEM>
STACK<ELEM>::~STACK( void)
{
        if( NULL!=this->base)
        {
                delete [](this->base);
                this->base = NULL;
        }
}

template <class ELEM>
bool STACK<ELEM>::push( ELEM item)
{
        if( (NULL==this->base)
            ||(this->top==this->cur))
                return false;

        this->cur ++;
        this->base[this->cur] = item;
        return true;
}

template <class ELEM>
bool STACK<ELEM>::pop( ELEM &item)
{
        if( (NULL==this->base)
            ||(this->cur<0))
                return false;

        item = this->base[this->cur];
        this->cur--;

        return true;
}

/**
*    This function is used to visit stack.
*/
template <class ELEM>
bool STACK<ELEM>::pop_v( ELEM &item)
{
        if( (NULL==this->base)
            ||(this->v_cur<0))
                return false;

        item = this->base[this->v_cur];
        this->v_cur--;

        return true;
}

/**
*    reset the posion of visit at current postion of stack.
*    That is necessary before use pop_v().
*/
template <class ELEM>
bool STACK<ELEM>::reset_v( void)
{
        this->v_cur = this->cur;
        return true;
}

#endif

2.2 Tool--map.h

/**

* Obviously, a map is necessary. By the help of the map, the boy could  concentrate on hisself‘s work rather than be busy with some things about map. That make the code is more clear and simple.

*/

/**
*    Map is a 2D matrix. For a element in the matrix, it compose by three parts:
*    X coordinate, Y coordinate and additional data in which we could save some
*    attribute information about this node.
*/
#ifndef MAP_H
#define MAP_H

#define MAP_MAX	15

typedef int    COORDINATE;

template <class NODE>
class MAP{
        public:
                MAP( int width);
                ~MAP( void);
                /*
            *    get a node which reside in [x,y]. The information of node
            *    will be write into @nod.
            */
                bool cur( COORDINATE x, COORDINATE y , NODE &nod);
                /*
            *    get a node reside in [ x-1, y].
            */
                bool left( COORDINATE x, COORDINATE y , NODE &nod);
                bool right( COORDINATE x, COORDINATE y, NODE &nod);
                bool up( COORDINATE x, COORDINATE y, NODE &nod);
                bool down( COORDINATE x, COORDINATE y, NODE &nod);
                /*
            *    set a map node
            */
                bool set( COORDINATE x, COORDINATE y, NODE &nod);

        private:
                /*
            *    point to the map
            */
                NODE    **p;
                int        wid;
};

/**
*    Init the size of map. Because we don't know any thing about the size,
*    nither width, nor height. So we use a trick.
*/
template <class NODE>
MAP<NODE>::MAP( int width)
{
        if( width>MAP_MAX)
        {
                this->p = NULL;
                return;
        }
        this->p = NULL;
#if 0
        this->p = ( NODE **)malloc( sizeof(NODE)*width*width);
#else
        this->p = new NODE*[width];
        for( int i=0; i<width; i++)
                this->p[i] = new NODE[width];
#endif
        this->wid = width;
}

template <class NODE>
MAP<NODE>::~MAP( void)
{
        if( NULL!=this->p)
        {
#if 0
                free (this->p);
#else
                for( int i=0; i<this->wid; i++)
                        delete []this->p[i];
                delete []this->p;
#endif
                this->p = NULL;
                this->wid = 0;
        }
}

template <class NODE>
bool MAP<NODE>::cur(COORDINATE x, COORDINATE y, NODE &nod)
{
        if( (x<0||x>=this->wid)
            ||(y<0||y>=this->wid))
                return false;

        nod =  this->p[x][y];
        return true;
}

template <class NODE >
bool MAP<NODE >::left( COORDINATE x, COORDINATE y, NODE &nod)
{
        if( (x<0||x>=this->wid)
            ||(y<=0||y>=this->wid))
                return false;

        nod =  this->p[ x][y-1];
        return true;
}

template <class NODE>
bool MAP<NODE>::right( COORDINATE x, COORDINATE y, NODE &nod)
{
        if( (x<0||x>=this->wid)
            ||(y<0||y>=this->wid-1))
                return false;

        nod = this->p[x][y+1];
        return true;
}

template <class NODE>
bool MAP<NODE>::up( COORDINATE x, COORDINATE y, NODE &nod)
{
        if( (x<=0||x>=this->wid)
            ||(y<0||y>=this->wid))
                return false;

        nod = this->p[x-1][y];
        return true;
}

template <class NODE>
bool MAP<NODE>::down( COORDINATE x, COORDINATE y, NODE &nod)
{
        if( (x<0||x>=this->wid-1)
            ||(y<0||y>=this->wid))
                return false;

        nod = this->p[x+1][y];
        return true;
}

template <class NODE>
bool MAP<NODE>::set( COORDINATE x, COORDINATE y, NODE &nod)
{
        if( (x<0||x>=this->wid)
            ||(y<0||y>=this->wid))
                return false;

        if( NULL==this->p)
        {
                return false;
        }

        this->p[x][y] = nod;
        return true;
}

#endif

2.3 Operator--boy

#include <stdio.h>
#include <iostream>

/**
*	To traverse the network totally, the little boy must ensure he can go back the same way.
*	So he save all of nodes,which he has been arrived,into a stack. The feature of stack is
*	first in, first out. That's what we lack.
*/
#include "../stack.h"

/**
*	Obviously, a map is necessary. By the help of the map, the boy could
*	concentrate on hisself's work rather than be busy with some things about map.
*	That make the code is more clear and simple.
*/
#include "map.h"

//map node
typedef unsigned char	UINT8;

#define MAP_WID	10
#define END_X	(MAP_WID-2)	//8
#define END_Y	(MAP_WID-2)	//8

#define STACK_DEPTH	200

enum ORIEN{
    O_RIGHT,
    O_DOWN,
    O_LEFT,
    O_UP,
    O_INVIALID,
    O_MAX,
};

enum TERRAIN {
    T_NOR = 0,
    T_BLOCK = 1,
    T_INVALID = 2,
};

/**
*    map information, 1 meaning for T_BLOCK. 0 meaning for T_NOR.
*/
static int	map_v[MAP_WID][MAP_WID] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1,
        1, 0, 0, 0, 0, 1, 1, 0, 0, 1,
        1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
        1, 0, 0, 0, 1, 0, 0, 0, 0, 1,
        1, 0, 1, 0, 0, 0, 1, 0, 0, 1,
        1, 0, 1, 1, 1, 0, 1, 1, 0, 1,
        1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};

/*
*    basic element in map was used to record all information about
*    a node.
*/
typedef  struct {
    COORDINATE	x;
    COORDINATE	y;
    TERRAIN	val;
    ORIEN	orien;
    bool		hasComing;
} ELEMENT;

/**
*    And this is that poor boy. He will provide a algorithm to solve
*    this maze problem. Of course, he need some tools: stack and
*    map.
*/
class BOY {
        public:
                BOY( void);
                ~BOY( void);
                /*
            *    begin to traverse this maze.
            */
                bool work( void);
                /*
            *    show information
            */
                bool ShowMap( void);
                bool ShowStack( void);

                private:
                /*
            *    two important functions, they compose the core of this algorithm.
            */
                bool forward( void);
                bool backward( void);
                /*
            *    work for those function above.
            */
                bool hasNBranch( ELEMENT &c_elem, ELEMENT &nod, ORIEN &from);	//has a new branch
                bool isEnd( void);			//arrive the end
                bool findVisible( ELEMENT &c_elem, ELEMENT &nod, ORIEN& from);
                bool wasCome( ELEMENT &c_elem);

                /*
            *    tool 1
            */
                MAP<ELEMENT>            map;
                /*
            *    tool 2
            */
                STACK<ELEMENT>        stack;
                /*
            *    current position
            */
                ELEMENT    cur;
};

BOY::BOY(void):map(MAP_WID), stack(STACK_DEPTH)
{
        cur.x = 1;
        cur.y = 1;
        cur.val = T_NOR;
        cur.orien = O_INVIALID;

        ELEMENT    tmp_elem;
        COORDINATE	i,j;
        for( i=0; i<MAP_WID; i++)
            for( j=0; j<MAP_WID; j++)
            {
                tmp_elem.x = i;
                tmp_elem.y = j;
                tmp_elem.orien = O_INVIALID;
                tmp_elem.hasComing = false;
                tmp_elem.val = ( TERRAIN)map_v[i][j];
                this->map.set( tmp_elem.x, tmp_elem.y, tmp_elem);
            }
}

BOY::~BOY( void)
{}

bool BOY::work(void)
{
        bool    isContinue = true;
        while( isContinue)
        {
                printf("this->cur[ %d, %d]\n", this->cur.x, this->cur.y);
                /*
            *    go ahead until encounter a dead end or arrive the exit.
            */
                while( this->forward( ))
                {
                        printf("this->cur[ %d, %d]\n", this->cur.x, this->cur.y);
                        if( this->isEnd( ) )
                                return true;
                }
                /*
            *    when the boy has encounter a dead end, he need to backtrack.
            *    find a valid path.
            */
                printf("back>\n");
                isContinue=this->backward( );
        }

        return false;
}

/**
*    based on current position, try to forward a step. If success, the previous postion
*    will be push in the stack. and update the information of past node  as arrived.
*    if fail, that meaning current node is a dead end.
*/
bool BOY::forward(void)
{
        ELEMENT    tmp_elem;
        ORIEN        tmp_from = O_RIGHT;

        if( !this->hasNBranch( this->cur, tmp_elem, tmp_from))
        {
                return false;
        }
        this->cur.orien = tmp_from;
        this->stack.push( this->cur);

        this->cur = tmp_elem;
        this->cur.hasComing = true;
        this->map.set( this->cur.x, this->cur.y, this->cur);

        return true;
}

/**
*    one of the core function. when the boy arrived a dead end,
*    this function will be call . It go back the same way untill find
*    a valid node that could give the little boy a new path(or a branch).
*/
bool BOY::backward(void)
{
        ELEMENT    tmp_elem;
        ORIEN        tmp_from = O_RIGHT;
        while( this->stack.pop( tmp_elem))
        {
                this->cur = tmp_elem;
                if( this->hasNBranch( this->cur, tmp_elem, tmp_from))
                {
                        return true;
                }
        }

        return false;
}

/**
*    check whether @c_elem node has a valid path that deserve to visit.
*    as same as other function, all information will be write into @elem
*    and @from.
*/
bool BOY::hasNBranch( ELEMENT &c_elem, ELEMENT &elem, ORIEN &from)
{
        ELEMENT    tmp_elem;
        ORIEN        tmp_from = from;
        while(1)
        {
                //find next visible position.
                        //Y:continue
                        //N:this node is a ending
                if( !this->findVisible( c_elem, tmp_elem, tmp_from))
                {
                        return false;
                }
                //was coming?
                        //Y:coninue
                        //N:right way
                if( !this->wasCome( tmp_elem))
                {//this is a new branch
                        break;
                }
                tmp_from =(ORIEN)( tmp_from + 1);		//next orientation
        }

        elem = tmp_elem;
        from = tmp_from;
        return true;
}

/**
*    arrive the exit of maze ?
*/
bool BOY::isEnd(void)
{
        if( (this->cur.x==END_X)
            &&(this->cur.y ==END_Y))
        {
                return true;
        }

        return false;
}

/**
*    find a visible path that is not block. It use @c_elem as the current view point,
*    if success , write information into @elem and @from.
*/
bool BOY::findVisible( ELEMENT &c_elem, ELEMENT &elem, ORIEN& from)
{
        ELEMENT	    tmp;
/*
*    check valid path clockwise.
*/
        switch( from)
        {
                case O_RIGHT:
                        if( (this->map.right( c_elem.x, c_elem.y, tmp))
                            &&( tmp.val == T_NOR))
                        {
                                elem = tmp;
                                from = O_RIGHT;
                                return true;
                        }
                case O_DOWN:
                        if( (this->map.down( c_elem.x, c_elem.y, tmp))
                                &&( tmp.val == T_NOR))
                            {
                                    elem = tmp;
                                    from = O_DOWN;
                                    return true;
                            }
                case O_LEFT:
                            if( (this->map.left( c_elem.x, c_elem.y, tmp))
                                &&( tmp.val == T_NOR))
                            {
                                    elem = tmp;
                                    from = O_LEFT;
                                    return true;
                            }
                case O_UP:
                            if( (this->map.up( c_elem.x, c_elem.y, tmp))
                                &&( tmp.val == T_NOR))
                            {
                                    elem = tmp;
                                    from = O_UP;
                                    return true;
                            }
                default :;
        }

        return false;
}

/**
*    Though this function is very tiny, it hold a important position
*    in the totally algorithm. The upper function will call this to ensure
*    whether a node is deserve to visit. By add a series of strategies
*    we could improve the algorithm.
*/
bool BOY::wasCome( ELEMENT &c_elem)
{
#if 1
        //label
        return c_elem.hasComing;
#else
	//标准1
	if( c_elem.hasComing)
		return true;

	//标准2
	ELEMENT	elem;
	this->stack.reset_v();
	while( this->stack.pop_v( elem))
	{
		if( (c_elem.x==elem.x)
			&&(c_elem.y==elem.y))
			return true;
	}

	return false;	//wasn't coming

#endif
}

/**
*    show the status of map
*/
bool BOY::ShowMap(void)
{
        printf("-----------MAP---------------------\n");
        COORDINATE    i,j;
        for( i=0; i<MAP_WID; i++)
        {
                for( j=0; j<MAP_WID; j++)
                {
                        ELEMENT	tmp;
                        if(!this->map.cur( i, j, tmp))
                        {
                                printf("error: [ %d, %d]\n", i, j);
                                return false;
                        }
                        printf("%3d", tmp.val);
                }
                printf("\n");
        }

        return true;
}

/**
*    show the status of stack, just visit it and don't pop element from it
*/
bool BOY::ShowStack(void)
{
        printf("-----------STACK---------------------\n");

        ELEMENT    tmp_elem;

        this->stack.reset_v( );
        while( this->stack.pop_v( tmp_elem))
        {
                printf("[ %d, %d]\n", tmp_elem.x, tmp_elem.y);
        }
}

int main()
{
        BOY    boy;
        boy.ShowMap( );
        boy.work( );
        boy.ShowStack( );
        return 0;
}

迷宫问题的C语言求解

时间: 2024-10-05 18:26:35

迷宫问题的C语言求解的相关文章

用R语言求解非线性方程

从本质上来说,Newtons就是用迭代方式,使近似解(泰勒公式)不断的逼近真实解,当满足精度要求时,即可认为近似解为真实解 下面用R语言实现Newtons法 Newtons<-function(fun,x,ep=1e-5,it_max=100) ##fun为需要求解的方程(组),x为初始解,ep为精度要求,it_max为最大迭代次数{ index<-0 ##指示是否完成迭代成功,满足精度要求 k<-1 ##迭代次数 while(k<=it_max) { x1<-x;obj&l

形如abcde/fghij = n 的表达式(C语言求解)

•题目:输入正整数n,按从小到大的顺序输出所有形如abcde/fghij=n的表达式,其中a~j恰好为数字0~9的一个排列,2<=n<=79 输入:62 输出:79546/01283=62 94736/01528=62 1 #include <stdio.h> 2 3 int main() 4 { 5 int n,x,y,temp;//a[10]={0}; 6 int i,j,flag; 7 scanf("%d",&n); 8 for(x=12345;x

Leetcode 24题 两两交换链表中的节点(Swap Nodes in Pairs))Java语言求解

题目描述: 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换. 示例: 给定 1->2->3->4,你应该返回 2->1->4->3. 注意事项 1.不能简单的交换数值,而是需要更改指针,即确实更改了节点: 2.如果节点个数是奇数,如下图: 那么第5个节点不用交换.只需变成如下图所示链表即可: 但是再考虑节点个数的奇偶,逻辑会比较麻烦: 3.在交换的过程中指针的指向如何更改也是一个问题. 如何交换

Leetcode 206题 反转链表(Reverse Linked List)Java语言求解

题目描述: 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 迭代解法 /** Definition for singly-linked list. public class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } */ class Solution { public ListNode

Leetcode 142题 环形链表 II(Linked List Cycle II) Java语言求解

题目描述: 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. 说明:不允许修改给定的链表. 分析 给出示意图: 对符号的一些说明: 公式演算: 很容易得到: m=x+y(环的长度两种表示形式); 快指针走两步,慢指针走一步.所以快指针的速度是慢指针的速度的二倍,所以相同时间内,快指针走的长度也是慢指针走的长度的二倍: 有:

Leetcode 141题 环形链表(Linked List Cycle) Java语言求解

题目描述: 给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. Map集合解法 思路: 创建一个map集合,key为节点,value为地址值,因为ListNode没有重写toString()方法,所以用toString()方法返回的内容作为value. 如果map中存在当前节点的toString()方法返回的内容,则存在环. /** * Definition for

LeetCode 232题用栈实现队列(Implement Queue using Stacks) Java语言求解

题目链接 https://leetcode-cn.com/problems/implement-queue-using-stacks/ 题目描述 使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部.pop() -- 从队列首部移除元素.peek() -- 返回队列首部的元素.empty() -- 返回队列是否为空. 示例: MyQueue queue = new MyQueue();queue.push(1);queue.push(2); queue.peek(); //

Leetcode 703题数据流中的第K大元素(Kth Largest Element in a Stream)Java语言求解

题目链接 https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/ 题目内容 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素.你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素.每次调用 KthLargest.add,返回当前数据流中第K大的元素. 示例: int k = 3; int[] arr = [4,5,8

Leetcode 239题 滑动窗口最大值(Sliding Window Maximum) Java语言求解

题目链接 https://leetcode-cn.com/problems/sliding-window-maximum/ 题目内容 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 输出: [3,3,5,5,6,7] 解释: 滑动窗口的位置|最大值 -|- [1 3 -1] -3 5