poj 3009

题意:

搜索,已知起点和终点,求石子从起点到达终点的最短路,如果无法到达,则输出-1。石子移动的具体规则如下:
   1、开始时,石子在起点s处
   2、运动方向可以是水平或垂直的,不能斜方向运动
   3、最开始的时候,你可以将石子向上下左右任意一个方向抛,如果与它相邻的点是障碍物的话除外
   4、一旦石子开始运动,有三种可能:
      a、遇到障碍物,石子会停在障碍物的前一格,障碍物会消失
      b、如果出界,游戏失败
      c、到达终点,游戏结束并成功
   5、如果移动的次数超过10次,将认为游戏是失败的

#include <iostream>
using namespace std;
 
const int MAX = 30;
int map[MAX][MAX];
int dir[4][2] = {{1,0}, {-1,0}, {0,1}, {0,-1}};
int R, C;
int ans;
 
bool InMap(int r, int c)
{
    return (r >= 1 && r <= R && c <= C && c >= 1);
}
 
void Dfs(int r, int c, int steps)
{
    int nr, nc;
    if (steps > 10 || steps > ans)
    {
        return ;
    }
    for (int i=0; i<4; i++)
    {
        nr = r;
        nc = c;
        // 不用担心越界问题:因为(nr,nc)在图的范围之内,而图又是从1开始编号,所以。。。
        if (map[nr+dir[i][0]][nc+dir[i][1]] != 1)
        {
            while (map[nr+dir[i][0]][nc+dir[i][1]] != 1)
            {
                // 下一步
                nr += dir[i][0];
                nc += dir[i][1];
                // 越界
                if (!InMap(nr, nc))
                {
                    break;
                }
                if (map[nr][nc] == 3)
                {
                    // 到达终点
                    if (steps + 1 < ans)
                    {
                        ans = steps + 1;
                    }
                    return ;
                }
            }
            if (InMap(nr, nc)) 
            {
                // 障碍
                map[nr+dir[i][0]][nc+dir[i][1]] = 0;
                Dfs(nr, nc, steps + 1);
                map[nr+dir[i][0]][nc+dir[i][1]] = 1;
            }
        }
    }
}
 
int main()
{
    int sr,sc;
    while (scanf("%d%d", &C, &R) && C && R)
    {
        memset(map, 0, sizeof(map));
        for (int r=1; r<=R; r++)
        {
            for (int c=1; c<=C; c++)
            {
                cin >> map[r][c];
                if (map[r][c] == 2)
                {
                    sr = r;
                    sc = c;
                }
            }
        }
        ans = 999999;
        Dfs(sr, sc, 0);
        (ans > 10) ? cout << "-1" << endl : cout << ans << endl; 
    }
    return 0;
}
/*DFS+Vector+剪枝*/

//TLE
//万恶的POJ好像和STL不兼容,剪枝还是超时
//vector的优势无法发挥啊。。。

#include<iostream>
#include<vector>
using namespace std;

const int inf=11;

typedef class
{
    public:
        int r,c;     //冰壶当前位置
        bool status; //status冰壶当前状态:运动true ,静止false
}SE;

SE s,e;   //记录冰壶起止点
int w,h;  //场地size
int MinStep;  //最短路

void DFS(vector<vector<int> >board,int i,int j,bool status,int direction,int step,bool flag)  
{ //direction:冰壶当前运动方向  North:0  West:1  South:2  East:3 
  //flag:是否消除direction方向下一格位置的石头

    if(step>10)   //剪枝,超过10步的走法就不再考虑了
        return;

    if(board[i][j]==3)   //终点
    {
        if(MinStep>step)
            MinStep=step;
        return;
    }

    if(flag)  //消除石头
    {
        switch(direction)
        {
            case 0: {board[i-1][j]=0; break;}     //board用vector表示的目的就是为了在当前步删除某位置的石头时
            case 1: {board[i][j-1]=0; break;}     //前一步并不会删除该位置的石头
            case 2: {board[i+1][j]=0; break;}
            case 3: {board[i][j+1]=0; break;}
        }
    }
    
    if(!status)  //静止
    {
        if(i-1>=1 && (board[i-1][j]==0 || board[i-1][j]==3))  //North
            DFS(board,i-1,j,true,0,step+1,false);

        if(j-1>=1 && (board[i][j-1]==0 || board[i][j-1]==3))  //West
            DFS(board,i,j-1,true,1,step+1,false);

        if(i+1<=h && (board[i+1][j]==0 || board[i+1][j]==3))  //South
            DFS(board,i+1,j,true,2,step+1,false);

        if(j+1<=w && (board[i][j+1]==0 || board[i][j+1]==3))  //East
            DFS(board,i,j-1,true,3,step+1,false);
    }
    else if(status)  //运动
    {
        switch(direction)
        {
            case 0:
                {
                    if(i-1<1)  //预判下一步是否越界
                        return;
                    else
                    {
                        if(board[i-1][j]==0)          //下一位置为0且不越界,继续运动
                            DFS(board,i-1,j,true,0,step,false);
                        else if(board[i-1][j]==1)          //下一位置为1且不越界,停止运动,并消除下一位置的石头
                            DFS(board,i,j,false,0,step,true);
                        else if(board[i-1][j]==3)          //下一位置为3且不越界,运动到位置3后停止运动,游戏结束
                            DFS(board,i-1,j,false,0,step,false);
                    }

                    break;
                }
            case 1:
                {
                    if(j-1<1)  //预判下一步是否越界
                        return;
                    else
                    {
                        if(board[i][j-1]==0)          //下一位置为0且不越界,继续运动
                            DFS(board,i,j-1,true,1,step,false);
                        else if(board[i][j-1]==1)          //下一位置为1且不越界,停止运动,并消除下一位置的石头
                            DFS(board,i,j,false,1,step,true);
                        else if(board[i][j-1]==3)          //下一位置为3且不越界,运动到位置3后停止运动,游戏结束
                            DFS(board,i,j-1,false,1,step,false);
                    }

                    break;
                }
            case 2:
                {
                    if(i+1>h)  //预判下一步是否越界
                        return;
                    else
                    {
                        if(board[i+1][j]==0)          //下一位置为0且不越界,继续运动
                            DFS(board,i+1,j,true,2,step,false);
                        else if(board[i+1][j]==1)          //下一位置为1且不越界,停止运动,并消除下一位置的石头
                            DFS(board,i,j,false,2,step,true);
                        else if(board[i+1][j]==3)          //下一位置为3且不越界,运动到位置3后停止运动,游戏结束
                            DFS(board,i+1,j,false,2,step,false);
                    }

                    break;
                }
            case 3:
                {
                    if(j+1>w)  //预判下一步是否越界
                        return;
                    else
                    {
                        if(board[i][j+1]==0)          //下一位置为0且不越界,继续运动
                            DFS(board,i,j+1,true,3,step,false);
                        else if(board[i][j+1]==1)          //下一位置为1且不越界,停止运动,并消除下一位置的石头
                            DFS(board,i,j,false,3,step,true);
                        else if(board[i][j+1]==3)          //下一位置为3且不越界,运动到位置3后停止运动,游戏结束
                            DFS(board,i,j+1,false,3,step,false);
                    }

                    break;
                }
        }
    }

    return;
}

int main(void)
{
    while(cin>>w>>h)
    {
        if(!w && !h)
            break;

        /*Structure the Board*/

        MinStep=inf;
        vector<vector<int> >board(h+1,vector<int>(w+1));

        for(int i=1;i<=h;i++)
            for(int j=1;j<=w;j++)
            {
                cin>>board[i][j];

                if(board[i][j]==2)
                {
                    s.r=i;
                    s.c=j;
                    s.status=false;
                    board[i][j]=0;  //记录起点位置后,把它作为0处理
                }
                if(board[i][j]==3)  //终点是特别位置,冰壶经过或到达该格都会停止
                {
                    e.r=i;
                    e.c=j;
                }
            }

        /*Search the min path*/

        DFS(board , s.r , s.c , s.status , 0 , 0 , false);

        if(MinStep<=10)
            cout<<MinStep<<endl;   //DFS里面虽然剪枝了,但是可能把全部走法都剪了,因此还是要判断
        else
            cout<<-1<<endl;

        /*Relax*/

    //    board.swap(vector<vector<int> >());      //POJ好像禁用swap()
    }
    return 0;
}

 

posted @ 2015-06-07 17:28  samjustin  阅读(137)  评论(0编辑  收藏  举报