zoukankan      html  css  js  c++  java
  • luogu P1519 穿越栅栏 Overfencing

    题目描述

    描述 农夫John在外面的田野上搭建了一个巨大的用栅栏围成的迷宫。幸运的是,他在迷宫的边界上留出了两段栅栏作为迷宫的出口。更幸运的是,他所建造的迷宫是一个“完美的”迷宫:即你能从迷宫中的任意一点找到一条走出迷宫的路。给定迷宫的宽度W(1<=W<=38)及高度H(1<=H<=100)。 2*H+1行,每行2*W+1的字符以下面给出的格式表示一个迷宫。然后计算从迷宫中最“糟糕”的那一个点走出迷宫所需的步数(就是从最“糟糕”的一点,走出迷宫的最少步数)。(即使从这一点以最优的方式走向最靠近的出口,它仍然需要最多的步数)当然了,牛们只会水平或垂直地在X或Y轴上移动,他们从来不走对角线。每移动到一个新的方格算作一步(包括移出迷宫的那一步)这是一个W=5,H=3的迷宫:

    +-+-+-+-+-+
    |         |
    +-+ +-+ + +
    |     | | |
    + +-+-+ + +
    | |     |  
    +-+ +-+-+-+

    如上图的例子,栅栏的柱子只出现在奇数行或奇数列。每个迷宫只有两个出口。

    输入输出格式

    输入格式:

     

    第一行: W和H(用空格隔开)

    第二行至第2 * H + 1行: 每行2 * W + 1个字符表示迷宫

     

    输出格式:

     

    输出一个单独的整数,表示能保证牛从迷宫中任意一点走出迷宫的最小步数。

    输入输出样例

    输入样例#1: 
    5 3
    +-+-+-+-+-+
    |         |
    +-+ +-+ + +
    |     | | |
    + +-+-+ + +
    | |     |  
    +-+ +-+-+-+
    输出样例#1: 
    9
    

    说明

    翻译来自NOCOW

    USACO 2.4

    刚读完题,感觉挺简单啊,不过研究了一下样例,一脸懵逼,这咋可能?。

    经过机房某位 S型 dalao(son)的解读,哦,so ga si nei,吆西吆西,interisting!!!

    再次就借花献佛了。

    关于的理解题意:

    为了便于理解,这里稍微修改一下题目。

    奇数行的栅栏(就是由‘+’和‘-’号组成)将其看做一层类似膜结构,一层防护膜(没有厚度),穿越不占距离。

    然后看偶数列,这里需要将偶数列和其两侧的‘-’看做一个整体,亦可以理解为忽略偶数列,只考虑奇数列。

    这里拿样例图解:

    结合上图,对题意理解就没什么问题了。

    解题剖析:

    1.读入含空格矩阵:

    想了半天,试了多种输入方法,最终貌似只有getline(:不会用戳我啊)可以用。

    但是在输入时,需要多输入一行,并且第一行和第二行会重复,其他没毛病,最后貌似没啥大碍。

        scanf("%d%d",&w,&h);
        w=w*2+1;h=h*2+1;
        for(int i=1;i<=h+1;i++)getline(cin,a[i]);

    读入是这样的,若有某位dalao明白以上出现的情况,希望讨论区不吝赐教。

    2.字符矩阵转换数字矩阵

    在这里定义一个int型map数组。

    map[i][j]表示走到这个点需要消耗的距离(偶数行为0,奇数行有空地的话消耗为1)

    在字符矩阵中[i][j]这个点为栅栏,不能走,将map[i][j]定义为2.

    注意前边说到,输入字符时会有一行多余,所以在转换时处理一下。

    此部分代码为:

        for(int i=2;i<=h+1;i++)
            for(int j=0;j<w;j++)
            {
                
                if(a[i][j]==32)
                {
                    if((i-1)%2==1)map[i-1][j+1]=0;
                    else if((j+1)%2==0)map[i-1][j+1]=1;
                    else map[i-1][j+1]=0;
                }
                else map[i-1][j+1]=2;
            }

    3.初始化:

    ans[i][j]数组记录走到 i,j这个点到出口的最近距离,栅栏处直接定义为-1。

    void initial()
    {
        for(int i=1;i<=h;i++)
            for(int j=1;j<=w;j++)
                if(map[i][j]==2)ans[i][j]=-1;
                else ans[i][j]=214748364;
    }

    4.找出出口:

    这没啥好说的,四个边找出口(注意经以上过程出口可能为0,可能为1)。

        for(int i=1;i<=w;i++)if(map[1][i]==0||map[1][i]==1)bfs(1,i);
        for(int i=1;i<=w;i++)if(map[h][i]==0||map[h][i]==1)bfs(h,i);
        for(int i=1;i<=h;i++)if(map[i][1]==0||map[i][1]==1)bfs(i,1);
        for(int i=1;i<=h;i++)if(map[i][w]==0||map[i][w]==1)bfs(i,w);

    5.大搜索

    已经处理处每一格的消耗距离,在搜索时,加上就好啦。

    两个出口,需要搜索两边所以搜完注意初始化,bool型数组。

    bool vis[N][M];
    struct ahah{
        int x,y;
    }str,cur;
    queue <ahah> que;
    void bfs(int x,int y)
    {
        ans[x][y]=0;
        vis[x][y]=1;
        str.x=x;str.y=y;
        que.push(str);
        while(!que.empty())
        {
            cur=que.front();
            que.pop() ;
            for(int i=0;i<4;i++)
            {
                str.x=cur.x+dx[i];
                str.y=cur.y+dy[i];
                if(map[str.x][str.y]!=2&&str.x>=1&&str.x<=h
                &&str.y>=1&&str.y<=w&&!vis[str.x][str.y])
                {
                    ans[str.x][str.y]=min(ans[cur.x][cur.y]+map[str.x][str.y],ans[str.x][str.y]);
                                
                    vis[str.x][str.y]=1;
                    que.push(str); 
                }
            }
        } 
        memset(vis,0,sizeof(vis));
    }

    6.找出最大值

    将ans数组循环一遍,找出最大值,输出即可。

    完整代码:

    /*.........................
    作者:Manjusaka
    时间:2018/7/11
    题目:P1519 Overfencing
    ..........................*/
    
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue> 
    using namespace std;
    #define N int(100)
    #define M int(210)
    int dx[5]={0,0,1,-1},dy[5]={1,-1,0,0};
    string a[N];
    int w,h,MAX;
    int x[4],y[4],k;
    int map[N][M];
    int ans[N][M];
    void check();
    void _scanf();
    void initial();
    void bfs(int ,int );
    void _scanf()
    {
        scanf("%d%d",&w,&h);
        w=w*2+1;h=h*2+1;
        for(int i=1;i<=h+1;i++)getline(cin,a[i]);
        for(int i=2;i<=h+1;i++)
            for(int j=0;j<w;j++)
            {
                
                if(a[i][j]==32)
                {
                    if((i-1)%2==1)map[i-1][j+1]=0;
                    else if((j+1)%2==0)map[i-1][j+1]=1;
                    else map[i-1][j+1]=0;
                }
                else map[i-1][j+1]=2;
            }
    //    cout<<"
    ";for(int i=1;i<=h;i++){for(int j=1;j<=w;j++){cout<<map[i][j];}cout<<endl;}
        check();
    }
    void check()
    {
        initial();    
        for(int i=1;i<=w;i++)if(map[1][i]==0||map[1][i]==1)bfs(1,i);
        for(int i=1;i<=w;i++)if(map[h][i]==0||map[h][i]==1)bfs(h,i);
        for(int i=1;i<=h;i++)if(map[i][1]==0||map[i][1]==1)bfs(i,1);
        for(int i=1;i<=h;i++)if(map[i][w]==0||map[i][w]==1)bfs(i,w);
        for(int i=1;i<=h;i++)
        {
            cout<<"
    ";
            for(int j=1;j<=w;j++)
            {
                printf("%3d",ans[i][j]);
            }
        }
    }
    void initial()
    {
        for(int i=1;i<=h;i++)
            for(int j=1;j<=w;j++)
                if(map[i][j]==2)ans[i][j]=-1;
                else ans[i][j]=214748364;
    }
    bool vis[N][M];
    struct ahah{
        int x,y;
    }str,cur;
    queue <ahah> que;
    void bfs(int x,int y)
    {
        ans[x][y]=0;
        vis[x][y]=1;
        str.x=x;str.y=y;
        que.push(str);
        while(!que.empty())
        {
            cur=que.front();
            que.pop() ;
            for(int i=0;i<4;i++)
            {
                str.x=cur.x+dx[i];
                str.y=cur.y+dy[i];
                if(map[str.x][str.y]!=2&&str.x>=1&&str.x<=h
                &&str.y>=1&&str.y<=w&&!vis[str.x][str.y])
                {
                    ans[str.x][str.y]=min(ans[cur.x][cur.y]+map[str.x][str.y],ans[str.x][str.y]);
                                
                    vis[str.x][str.y]=1;
                    que.push(str); 
                }
            }
        } 
        memset(vis,0,sizeof(vis));
    }
    void _printf()
    {
        for(int i=1;i<=h;i++)
            for(int j=1;j<=w;j++)
                MAX=max(MAX,ans[i][j]);
        printf("
    %d",MAX);
    }
    int main()
    {
        _scanf();
        _printf();
    }

    求助大佬!!:

    按题目要求来说二位数组开到100*200应该完全可以啊,为什么会比RE,求解释。

  • 相关阅读:
    Javascript 使用字符串
    JavaScript精简学习4(动态表单和链接处理)
    JavaScript 使用表单
    事半功倍之Javascript (2)
    jQuery隐藏按钮
    .NET线程同步之Interlocked和ReadWrite 锁线程同步——事件构造
    linux命令汇总
    好的设计能减少大量的工作
    Prism学习笔记
    编写C函数的技巧
  • 原文地址:https://www.cnblogs.com/rmy020718/p/9297006.html
Copyright © 2011-2022 走看看