poj 3083 Children of the Candy C…

Description

The cornfield maze is a popular Halloween treat.Visitors are shown the entrance and must wander through the mazefacing zombies, chainsaw-wielding psychopaths, hippies, and otherterrors on their quest to find the exit. 

One popular maze-walking strategy guarantees that the visitor willeventually find the exit. Simply choose either the right or leftwall, and follow it. Of course, there's no guarantee which strategy(left or right) will be better, and the path taken is seldom themost efficient. (It also doesn't work on mazes with exits that arenot on the edge; those types of mazes are not represented in thisproblem.) 

As the proprieter of a cornfield that is about to be converted intoa maze, you'd like to have a computer program that can determinethe left and right-hand paths along with the shortest path so thatyou can figure out which layout has the best chance of confoundingvisitors.

Input

Input to this problem will begin with a linecontaining a single integer n indicating the number of mazes. Eachmaze will consist of one line with a width, w, and height, h (3<= w, h <= 40), followed by h lines of w characters each thatrepresent the maze layout. Walls are represented by hash marks('#'), empty space by periods ('.'), the start by an 'S' and theexit by an 'E'. 

Exactly one 'S' and one 'E' will be present in the maze, and theywill always be located along one of the maze edges and never in acorner. The maze will be fully enclosed by walls ('#'), with theonly openings being the 'S' and 'E'. The 'S' and 'E' will also beseparated by at least one wall ('#'). 

You may assume that the maze exit is always reachable from thestart point.

Output

For each maze in the input, output on a singleline the number of (not necessarily unique) squares that a personwould visit (including the 'S' and 'E') for (in order) the left,right, and shortest paths, separated by a single space each.Movement from one square to another is only allowed in thehorizontal or vertical direction; movement along the diagonals isnot allowed.

Sample Input


8 8 
######## 
#......# 
#.####.# 
#.####.# 
#.####.# 
#.####.# 
#...#..# 
#S#E#### 
9 5 
######### 
#.#.#.#.# 
S.......E 
#.#.#.#.# 
#########

Sample Output

37 5 5 
17 17 9


这个题..呵呵....

第一次做了深搜.恩= =

求最小步数用广搜.这个没什么好说的了.就是在于深搜求左边路线与右边路线的问题.深搜时候,重点是要确立方向.
用一个变量dl记录上一次朝向的方向.比如上一次是向上走的,那么这一次应该向左,向上,向右,向下.用1,2,3,4表示左上右下.右深搜也一样.
还需要注意的一点就是不用标记.因为走过的路可以再走.



#include
#include
using namespace std;

char a[43][43], vis[43][43];
int dirx[4] = {-1,0,1,0}, diry[4] = {0, 1, 0, -1}, mi, dl, dr,lp, f1, rp, f2;
typedef struct node
{
    int x, y, step;
}node;


void dfsl(int x, int y, int dl)
{
    if(a[x][y] == 'E')
    {
       f1 = 1;                                  //f1为1时,即找到左搜的可行解.立刻返回
       return;
    }
    if(a[x][y] == '#')
       return;

    if(!f1)
    {
       lp++;                           //lp表示步数.与标记法不同的是,这里的lp需要在每找到一个可行点就加1,不需要根据这个点是否在路径上.
    switch(dl)
    {
    case 1:
       dfsl(x+1, y, 4);
       dfsl(x, y-1, 1);
       dfsl(x-1, y, 2);
       dfsl(x, y+1, 3);
       break;
    case 2:
       dfsl(x, y-1, 1);
       dfsl(x-1, y, 2);
       dfsl(x, y+1, 3);
       dfsl(x+1, y, 4);
       break;
    case 3:
       dfsl(x-1, y, 2);
       dfsl(x, y+1, 3);
       dfsl(x+1, y, 4);
       dfsl(x, y-1, 1);
       break;
    case 4:
       dfsl(x, y+1, 3);
       dfsl(x+1, y, 4);
       dfsl(x, y-1, 1);
       dfsl(x-1, y, 2);
       break;
    }
    }

}
void dfsr(int x, int y, int dr)
{
    if(a[x][y] == 'E')
    {
       f2 = 1;
       return;
    }
    if(a[x][y] == '#')
       return;

    if(!f2)
    {
       rp++;
    switch(dr)
    {
    case 1:
       dfsr(x+1, y, 4);
       dfsr(x, y+1, 1);
       dfsr(x-1, y, 2);
       dfsr(x, y-1, 3);
       break;
    case 2:
       dfsr(x, y+1, 1);
       dfsr(x-1, y, 2);
       dfsr(x, y-1, 3);
       dfsr(x+1, y, 4);
       break;
    case 3:
       dfsr(x-1, y, 2);
       dfsr(x, y-1, 3);
       dfsr(x+1, y, 4);
       dfsr(x, y+1, 1);
       break;
    case 4:
       dfsr(x, y-1, 3);
       dfsr(x+1, y, 4);
       dfsr(x, y+1, 1);
       dfsr(x-1, y, 2);
       break;
    }
    }

}


int bfs(int x, int y)
{
    int i;
    queue node q;
    node u;
    u.x = x;         //处理第一个点,即起点.
    u.y = y;
    u.step = 1;
    vis[x][y] = 1;
    q.push(u);         //将起点压栈
    while(!q.empty())      
    {
       //printf("yes\n");
       u = q.front();           //取栈顶元素,然后将这个点四周的可行点压栈
       //printf("%d %d %d\n", u.x, u.y, u.step);
       q.pop();
       if(a[u.x][u.y] == 'E')
           returnu.step;
       for(i = 0 ; i < 4 ; i++)
       {
           nodev;
           v.x = u.x+ dirx[i];
           v.y = u.y+ diry[i];
          if(vis[v.x][v.y] != 1 && a[v.x][v.y] != '#')
           {
              //printf("%d %d\n", v.x,v.y);
              vis[v.x][v.y] = 1;
              v.step = u.step+1;                  //四周每个可行点的step都是一样的,都是中心点的step+1
              q.push(v);
           }
       }
    }
    return 0;
}

int main()
{
    int t, m, n, i, j,flag;
    scanf("%d",&t);
    while(t--)
    {
       f1 = 0;
       f2 = 0;
       lp = 1;
       rp = 1;
       flag = 0;
       scanf("%d %d", &n, &m);
       for(i = 0 ; i <= m+1 ; i++ )
           for(j = 0; j <= n+1 ; j++)
           vis[i][j]= 0;
       for(i = 1 ; i <= m ; i++)
       {
          getchar();
           for(j = 1; j <= n ; j++)
          scanf("%c", &a[i][j]);
       }
       for(i = 0 ; i <= n+1 ; i++)
       {
           a[0][i] ='#';
           a[m+1][i]= '#';
       }
       for(i = 0 ; i <= m+1 ; i++)
       {
           a[i][0] ='#';
           a[i][n+1]= '#';
       }
       for(i = 0 ; i <= m && !flag;i++)
           for(j = 0; j <= n ; j++)
           if(a[i][j]== 'S')
       {
           if(i ==1)
              dl = dr = 2;
           else if(j== 1)
           {
                dl =1;
                dr =3;
           }
           else if(i== m)
              dl = dr = 4;
           else if(j== n)
           {
               dl =3;
               dr =1;
           }

           dfsl(i, j,dl);
           dfsr(i, j,dr);
           mi =bfs(i, j);
           flag =1;
          break;
       }
       printf("%d %d %d\n", lp, rp, mi);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值