FZUOJ 2250 不可能弹幕结界【思维+Bfs】

224 篇文章 2 订阅
 
 Problem 2250 不可能弹幕结界

Accept: 18    Submit: 50
Time Limit: 1000 mSec    Memory Limit : 65536 KB

 Problem Description

咲夜需要穿过一片弹幕区,由于咲夜发动了符卡“The World”,所以弹幕是静止的。这片弹幕区以一个n*m的矩阵的形式给出。

‘.’表示这个位置是安全的,’x’表示这个位置上是有子弹的,禁止通行。咲夜每次能向左、右、下三个方向的相邻格子走,但是不能向上走。 同时由于时间有限,咲夜在进入每一行之后最多只能横向走k步。你可以简单地认为我们的目标就是从第0行走到第n+1行,起点和终点可以是在第0行和第n+1行的任意位置,当然第0行和第n+1行都是没有弹幕的。

然而这是号称不可能的弹幕结界,所以咲夜很可能无法穿过这片弹幕,所以咲夜准备了一个只能使用一次的技能,纵向穿越,她可以从任意位置直接穿越到另外任意一行的同一个位置(所在列不变),当然她只能向下穿越,不能向上穿越。穿越的距离越远,耗费的资源自然越多,所以她想知道最短的穿越距离,才能使她成功通过这片弹幕区。

 Input

输入包含多组数据。

对于每组数据:

第一行输入三个整数n,m,k,如上所述。

接下下输入一个n×m的矩阵,’.’表示当前这格没有子弹,是安全的,’x’表示这各有子弹,禁止通行。

N<=1000,k<=m<=1000

 Output

对于每组数据输出一个整数,表示最短的穿越距离。

 Sample Input

6 5 2x.x....xx..xxx.xx.xxxx..x..x.x4 4 1.xxx.xxx...xxx.x

 Sample Output

32

 Hint

对于第一组样例,最优解是从第一行第二列走到第三行第一列,然后跳到第6行第一列,穿越距离为(6 – 3) = 3。

long long类型请用%I64d输出

 Source

FOJ有奖月赛-2017年4月(校赛热身赛)


思路:

1、我们首先从起点开始Bfs.这里需要维护一个到达每个点的最小横向行走步数。
即我们可以设定vis【i】【j】=x:表示从起点开始走到i,j这个位子是否能够走到,如果能够走到x值为走到这个点的最小横向走的步数,否则设定为INF。

2、那么我们预处理两次Bfs,一次从起点出发向下走,另一次从终点出发向上走。
那么得到vis【i】【j】和vis2【i】【j】;
然后维护每一列两个元素:一列中从上到下最远能够走到的地方posup,以及一列中从下到上最远能够走到的地方posdown.
那么ans=min(ans,posdown-posup);
过程维护一下即可。

3、注意几个坑:
①可能整个图都是x.
②起点本身是第0行,输入的是第1行。
所以类似:
6 5 0
x.x..
...x.
.x.x.
xx.xx
....x
x...x
的正解应该是2.
③如果整个图是连通的,那么直接输出0.
④如果整个图不是连通的,并且出现了posdown==posup的情况,其结果不应该是0.因为本身就是一个交汇点出现了而已,所以posdown要求大于posup.
...................
大家多想想细节就行了,我能够想到的就这么些、希望能够帮到Wa到死的同学= =

Ac代码:

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct node
{
    int x,y,step;
}now,nex;
char a[1005][1005];
int vis[1005][1005];
int vis2[1005][1005];
int fx[3]={0,0,1};
int fy[3]={1,-1,0};
int fx2[3]={0,0,-1};
int fy2[3]={1,-1,0};
int n,m,k;
void Bfss()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            vis[i][j]=0x3f3f3f3f;
        }
    }
    queue<node>s;
    for(int i=0;i<m;i++)
    {
        if(a[0][i]=='.')
        {
            now.x=0;
            now.y=i;
            now.step=0;
            s.push(now);
            vis[now.x][now.y]=0;
        }
    }
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<3;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(i==2)nex.step=0;
            else nex.step=now.step+1;
            if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&nex.step<=k&&a[nex.x][nex.y]!='x')
            {
                if(vis[nex.x][nex.y]>nex.step)
                {
                    vis[nex.x][nex.y]=nex.step;
                    s.push(nex);
                }
            }
        }
    }
}
void Bfst()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            vis2[i][j]=0x3f3f3f3f;
        }
    }
    queue<node>s;
    for(int i=0;i<m;i++)
    {
        if(a[n-1][i]=='.')
        {
            now.x=n-1;
            now.y=i;
            now.step=0;
            s.push(now);
            vis2[now.x][now.y]=0;
        }
    }
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<3;i++)
        {
            nex.x=now.x+fx2[i];
            nex.y=now.y+fy2[i];
            if(i==2)nex.step=0;
            else nex.step=now.step+1;
            if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&nex.step<=k&&a[nex.x][nex.y]!='x')
            {
                if(vis2[nex.x][nex.y]>nex.step)
                {
                    vis2[nex.x][nex.y]=nex.step;
                    s.push(nex);
                }
            }
        }
    }
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        for(int i=0;i<n;i++)scanf("%s",a[i]);
        Bfss();
        Bfst();
        int flag=0;
        for(int i=0;i<m;i++)
        {
            if(vis[n-1][i]!=0x3f3f3f3f)flag=1;
        }
        if(flag==1)
        {
            printf("0\n");
            continue;
        }
        int ans=n+1;
        for(int i=0;i<m;i++)
        {
            int posup=-1;
            int posdown=-1;
            for(int j=0;j<n;j++)
            {
                if(vis[j][i]!=0x3f3f3f3f)posup=j;
                if(vis2[j][i]!=0x3f3f3f3f&&posdown==-1)posdown=j;
            }
            if(posup!=-1)ans=min(ans,n-posup);
            if(posup==-1&&posdown!=-1)ans=min(ans,posdown+1);
            if(posup==-1||posdown==-1)continue;
            else
            {
                if(posdown==posup)
                {
                    for(int j=0;j<n;j++)
                    {
                        if(vis2[j][i]!=0x3f3f3f3f&&j!=posup)ans=min(ans,j-posup);
                    }
                }
                else ans=min(ans,posdown-posup);
            }
        }
        printf("%d\n",ans);
    }
}







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值