• 【BZOJ-1656】The Grove 树木 BFS + 射线法


    1656: [Usaco2006 Jan] The Grove 树木

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 186  Solved: 118
    [Submit][Status][Discuss]

    Description

    The pasture contains a small, contiguous grove of trees that has no 'holes' in the middle of the it. Bessie wonders: how far is it to walk around that grove and get back to my starting position? She's just sure there is a way to do it by going from her start location to successive locations by walking horizontally, vertically, or diagonally and counting each move as a single step. Just looking at it, she doesn't think you could pass 'through' the grove on a tricky diagonal. Your job is to calculate the minimum number of steps she must take. Happily, Bessie lives on a simple world where the pasture is represented by a grid with R rows and C columns (1 <= R <= 50, 1 <= C <= 50). Here's a typical example where '.' is pasture (which Bessie may traverse), 'X' is the grove of trees, '*' represents Bessie's start and end position, and '+' marks one shortest path she can walk to circumnavigate the grove (i.e., the answer): ...+... ..+X+.. .+XXX+. ..+XXX+ ..+X..+ ...+++* The path shown is not the only possible shortest path; Bessie might have taken a diagonal step from her start position and achieved a similar length solution. Bessie is happy that she's starting 'outside' the grove instead of in a sort of 'harbor' that could complicate finding the best path.

    牧场里有一片树林,林子里没有坑.
        贝茜很想知道,最少需要多少步能围绕树林走一圈,最后回到起点.她能上下左右走,也能走对角线格子.牧场被分成R行C列(1≤R≤50,1≤C≤50).下面是一张样例的地图,其中“.”表示贝茜可以走的空地,  “X”表示树林,  “*”表示起点.而贝茜走的最近的路已经特别地用“+”表示出来.
     
     
     
     
     
    题目保证,最短的路径一定可以找到.

    Input

    * Line 1: Two space-separated integers: R and C

    * Lines 2..R+1: Line i+1 describes row i with C characters (with no spaces between them).

        第1行输入R和C,接下来R行C列表示一张地图.地图中的符号如题干所述.

    Output

    * Line 1: The single line contains a single integer which is the smallest number of steps required to circumnavigate the grove.

        输出最少的步数.

    Sample Input

    6 7
    .......
    ...X...
    ..XXX..
    ...XXX.
    ...X...
    ......*

    Sample Output

    13

    HINT

    Source

    Silver

    Solution

    显然是bfs,但是要求绕障碍一周,所以不能裸上bfs。

    考虑从障碍向边界引出一个阻拦边,规定,这个阻拦边右边的点无法穿过该边,但是左边的点可以穿过,这样就可以用这条边来限制,使得可以得到绕圈一周的答案。

    具体的方法就是,对于每个点记录dis[0/1][x][y]表示从右/左来的距离,这样在bfs的时候分类讨论一下,就可以了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    using namespace std;
    int N,M,sx,sy,lx,ly,dis[2][51][51];
    struct Pa{int x,y,d;};
    int dx[9]={0,0,0,1,1,1,-1,-1,-1},dy[9]={0,1,-1,0,1,-1,0,1,-1};
    bool visit[51][51],mp[51][51],line[51][51];
    inline bool OK(int x,int y) {return x>=1 && x<=N && y>=1 && y<=M;}
    void BFS()
    {
        queue<Pa>q; q.push((Pa){sx,sy,0}); dis[0][sx][sy]=1;
        while (!q.empty())
            {
                Pa now=q.front(); q.pop();
                for (int d=1,x,y; d<=8; d++)
                    {
                        x=now.x+dx[d],y=now.y+dy[d];
                        if (!OK(x,y) || mp[x][y]) continue;
                        if (line[now.x][now.y] && y<=now.y) continue;
                        if (line[x][y] && y>now.y)
                            if (!dis[1][x][y]) 
                                dis[1][x][y]=dis[0][now.x][now.y]+1,q.push((Pa){x,y,1}); 
                            else;
                        else
                            if (!dis[now.d][x][y]) 
                                dis[now.d][x][y]=dis[now.d][now.x][now.y]+1,q.push((Pa){x,y,now.d}); 
                            else;
                    }
            }
    }
    int main()
    {
        scanf("%d%d",&N,&M); char c[51][51];
        for (int i=1; i<=N; i++)
            {
                scanf("%s",c[i]+1);
                for (int j=1; j<=M; j++)
                    mp[i][j]=c[i][j]=='X',lx=c[i][j]=='X'? i:lx,ly=c[i][j]=='X'? j:ly,
                    sx=c[i][j]=='*'? i:sx,sy=c[i][j]=='*'? j:sy;
            }
        for (int i=1; i<=N; i++) if (i+lx<=N) line[i+lx][ly]=1;
        BFS();
        printf("%d
    ",dis[1][sx][sy]-1);
        return 0;
    }

    说好了shabi题不发博客...

    然而长这么大没写过这样的bfs...

    自己明明想到了,却实现出了问题,在讨论的时候naive了....所以留一下长记性

  • 相关阅读:
    14 break
    13 for循环
    Python 3.7 将引入 dataclass 装饰器
    工程师如何在面试中脱颖而出
    如何避免 async/await 地狱
    命令行里打 cd 简直是浪费生命
    GitHub 十大 CI 工具
    GitHub CEO:GitHub 十年,感谢有你
    如何在 2 分钟内入睡(二战时期美国飞行员训练法)
    一分钟了解 TCP/IP 模型
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6001946.html
Copyright © 2020-2023  润新知