您的位置:首页 > 编程语言 > C语言/C++

一个箱子的推箱子算法

2015-07-28 10:04 302 查看
Pushing Boxes
Description
Imagine you arestanding inside a two-dimensional maze composed of square cells which may ormay not be filled with rock. You can move north, south, east or west one cellat a step. These moves are called walks. 

One of the empty cells contains a box which can be moved to an adjacent freecell by standing next to the box and then moving in the direction of the box.Such a move is called a push. The box cannot be moved in any other way than bypushing, which means that
if you push it into a corner you can never get it outof the corner again. 

One of the empty cells is marked as the target cell. Your job is to bring thebox to the target cell by a sequence of walks and pushes. As the box is veryheavy, you would like to minimize the number of pushes. Can you write a programthat will work out the best
such sequence? 

Input
The input containsthe descriptions of several mazes. Each maze description starts with a linecontaining two integers r and c (both <= 20) representing the number of rowsand columns of the maze. 

Following this are r lines each containing c characters. Each characterdescribes one cell of the maze. A cell full of rock is indicated by a `#' andan empty cell is represented by a `.'. Your starting position is symbolized by`S', the starting position of the
box by `B' and the target cell by `T'. 

Input is terminated by two zeroes for r and c. 
Output
For each maze inthe input, first print the number of the maze, as shown in the sample output.Then, if it is impossible to bring the box to the target cell, print ``Impossible.''. 

Otherwise, output a sequence that minimizes the number of pushes. If there ismore than one such sequence, choose the one that minimizes the number of totalmoves (walks and pushes). If there is still more than one such sequence, anyone is acceptable. 

Print the sequence as a string of the characters N, S, E, W, n, s, e and wwhere uppercase letters stand for pushes, lowercase letters stand for walks andthe different letters stand for the directions north, south, east and west. 

Output a single blank line after each test case. 
Sample Input
1 7
SB....T
1 7
SB..#.T
7 11
###########
#T##......#
#.#.#..####
#....B....#
#.######..#
#.....S...#
###########
8 4
....
.##.
.#..
.#..
.#.B
.##S
....
###T
0 0
Sample Output
Maze #1
EEEEE
 
Maze #2
Impossible.
 
Maze #3
eennwwWWWWeeeeeesswwwwwwwnNN
 
Maze #4
swwwnnnnnneeesssSSS
 

 

题目意思:很简单,推箱子。给出步骤最少的一种方案即可

解题思路:本题宜采用优先队列,使得步骤越少其优先级越高。关键在于处理son数组的问题。

具体代码如下:

 

#include<iostream>

#include<queue>

usingnamespace std;

 

#definemax 22 //行和列的最大值

 

 

structS

{

    int x,y;//人所在的坐标位置

    int bx,by;//箱子所在的坐标位置

    int id;//唯一标识T

    int pcnt;//人移动的步数

    int bcnt;//箱子移动的步数

    friend bool operator<(struct S a,struct Sb); //运算符重载,用来判断a和b的优先顺序

};

booloperator<(struct S a,struct S b);

voiddfs(int x) ;//递归的方式输出结果

priority_queue<S>que;//存放着符合提议的方案

charvalue[max][max];//存储迷宫的输入

boolisvisit[max][max][max][max];//此四维数组记录的是人的位置和箱子的位置是否走过

S t;

intson[1000000];//记录的是结点先后录入的顺序

charval[1000000];//记录一种行进路线

intmain()

{

    int nexted[4][2];

    nexted[0][0]=0;

    nexted[0][1]=1;//东

    nexted[1][0]=1;

    nexted[1][1]=0;//南

    nexted[2][0]=0;

    nexted[2][1]=-1;//西

    nexted[3][0]=-1;

    nexted[3][1]=0;//北

    int r,c;//r代表迷宫的行,c代表迷宫的列

    cin>>r>>c;

    int tx,ty;//表示箱子的目标位置

    int idx;//递增的id,用来为t的id赋值

    int casenum=1;

    while((r!=0)||(c!=0))

    {

        for(int i=0;i<max;i++)

        {

            for(int j=0;j<max;j++)

            {

                for(int k=0;k<max;k++)

                {

                    for(int t=0;t<max;t++)

                    {

                        isvisit[i][j][k][t]=false;

                    }

                }

            }

        }

        for(int i=0;i<r;i++)

        {

            for(int j=0;j<c;j++)

            {

                cin>>value[i][j];

                if(value[i][j]=='S')

                {

                    value[i][j]= '.';  //此点为可行点

                    t.x=i;

                    t.y=j;//记录下人开始的位置

                }

                if(value[i][j]=='B')

                {

                    value[i][j]='.';//此点为可行点

                    t.bx=i;

                    t.by=j;//记录下箱子开始的位置

                }

                if(value[i][j]=='T')

                {

                    value[i][j]='.';//此点为可行点

                    tx=i;

                    ty=j;//记录目标位置

                }

            }

        }

       

        cout<<"Maze#"<<casenum<<endl;

        casenum+=1;

        isvisit[t.x][t.y][t.bx][t.by]=true;//标记初始点

        t.id=0;//第一个点

        t.pcnt=0;//显然为0

        t.bcnt=0;

        idx=1;//为下个id做准备

        son[0]=-1;//表示结束的标识

        while(!que.empty())

        {

            //清空队列,防止上次的结果对这次的影响

            que.pop();

        }

        que.push(t);

        while(!que.empty())
b960

        {

            t=que.top();

            if((t.bx==tx)&&(t.by==ty))

            {

                //箱子的位置已经在目标位置上了

                dfs(t.id); 

                cout<<endl;

                break;

            }

            //for循环为判断当前点有几种选择

            for(int i=0;i<4;i++)

            {

                //每次移动只有四个选择

                t.x+=nexted[i][0];

                t.y+=nexted[i][1];

                if((t.x>=0)&&(t.x<r)&&(t.y>=0)&&(t.y<c)&&(value[t.x][t.y])=='.')

                {

                    //如果人的下一位置可以行走的话,人有两种选择,1、前进一步,2、推箱子并行进一步

                    if((t.x==t.bx)&&(t.y==t.by))

                    {

                        //箱子和人处于同一位置,就推箱子

                        t.bx+=nexted[i][0];

                        t.by+=nexted[i][1];

                        if((t.bx>=0)&&(t.bx<r)&&(t.by>=0)&&(t.by<c)&&(value[t.bx][t.by]=='.'))

                        {

                            //判断箱子能否推

                            if(!isvisit[t.x][t.y][t.bx][t.by])

                            {

                                //以前没有走过这个节点

                                isvisit[t.x][t.y][t.bx][t.by]=true;

                                //先将下一个可行点入优先队列,然后在恢复当前结点

                                intoldid=t.id; 

                                son[idx]=t.id; 

                                t.id=idx; 

                                t.pcnt++; 

                                t.bcnt++; 

                                if(i==0)val[idx]='E'; 

                                if(i==1)val[idx]='S'; 

                                if(i==2)val[idx]='W'; 

                                if(i==3)val[idx]='N'; 

                                que.push(t); 

                                t.pcnt--; 

                                t.bcnt--; 

                                idx++; 

                                t.id=oldid;

                            }

                        }

                        //箱子回退,寻找其他路径

                        t.bx-=nexted[i][0];

                        t.by-=nexted[i][1];

                    }

                    else

                    {

                        if(!isvisit[t.x][t.y][t.bx][t.by]) 

                        { 

                           isvisit[t.x][t.y][t.bx][t.by]=1; 

                            intoldid=t.id; 

                            son[idx]=t.id; 

                            t.id=idx; 

                            t.bcnt++; 

                            if(i==0)val[idx]='e'; 

                            if(i==1)val[idx]='s'; 

                            if(i==2)val[idx]='w'; 

                            if(i==3)val[idx]='n'; 

                            que.push(t); 

                            t.bcnt--; 

                            idx++; 

                            t.id=oldid;

                        }

                    }

                }

                //人回退

                t.x-=nexted[i][0];

                t.y-=nexted[i][1];

            }

            que.pop();

        }

        if(que.empty())

        {

            cout<<"Impossible."<<endl;

        }

        cout<<endl;

        cin>>r>>c;

    }

    return 0;

}

booloperator<(struct S a,struct S b)



    if(a.pcnt!=b.pcnt) returna.pcnt>b.pcnt; 

    else return a.bcnt>b.bcnt; 

}

voiddfs(int x) 



    if(son[x]!=-1) 

    { 

        dfs(son[x]); 

        cout<<val[x];

    } 

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ 动态规划