July 15th 模拟赛C T4 回家(莫名其妙【推荐】) Solution

本文介绍了一个有趣的问题:如何帮助Alice在充满怪兽的森林中找到最安全的路径回家。通过使用SPFA算法预处理危险系数,并结合二分查找与BFS算法验证路径可行性,最终确定最优解。

空降题目处
点我点我点我

Description:

Alice住在森林里,森林可以看作是N*M的网格,森林里有怪兽,用‘.’表示空地,‘+’表示怪兽,‘V’表示Alice现在的位置,‘J’表示Alice的家。
Alice可以从当前单元格向上下左右相邻单元格移动,有怪兽的地方也可以走,只不过比较危险,有怪兽的单元格对其他单元格会产生一定的危险系数,假设怪兽位置为(A,B),它对某单元格(R,C)的危险系数为:|R-A|+|C-B|,危险系数越小越危险,每个单元格的危险系数是所有怪兽对它产生的系数的最小值。
Alice请你帮她找一条最佳路径回家,即使得路径上经过单元格的最小的危险系数最大。

Input

输入第一行包含两个整数N和M(1<=N,M<=500),表示森林的大小。
接下来N行每行包含M个字符:‘.’,‘+’,‘V’,‘J’。
输入只包含一个‘V’和‘J’,而且至少有一个‘+’。

Output

输出最佳路径中最小的危险系数。

Solution

将Monster的位置存入队列,作为初始状态,利用SPFA更新出矩阵的危险系数. (危险系数越大越安全?智障?)
二分答案,利用Bfs检索合法性.

Program

C++

#include<iostream>
#include<fstream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;

int n,m,sx,sy,ex,ey,t,l[501][501],d[1000001][3];
string c;
int me[5][3]={{0,0,0},{0,0,1},{0,1,0},{0,-1,0},{0,0,-1}};
bool bj[501][501];

void SPFA(int j);
bool Bfs(int q);
int FF(int l,int r);

int main()
{
    memset(l,10000,sizeof(l));
    scanf("%d%d\n",&n,&m);
    for (int i=1;i<=n;i++)
    {
        cin>>c;
        for (int j=1;j<=m;j++)
        {
            switch (c[j-1])
            {
                case '+':
                    t++;
                    d[t][1]=i;
                    d[t][2]=j;
                    bj[i][j]=true;
                    l[i][j]=0;
                break;
                case 'V':
                    sx=i;
                    sy=j;
                break;
                case 'J':
                    ex=i;
                    ey=j;
                break;
            }
        }
        //scanf("\n");
    }
    SPFA(t);
    printf("%d",FF(0,n+m));
}

void SPFA(int j)
{
    int i=0,p,q;
    while (i<j)
    {
        i++;
        for (int k=1;k<=4;k++)
        {
            p=d[i][1]+me[k][1];
            q=d[i][2]+me[k][2];
            if ((p>0)&&(p<n+1)&&(q>0)&&(q<m+1))
            {
                if (l[d[i][1]][d[i][2]]+1<l[p][q])
                {
                    l[p][q]=l[d[i][1]][d[i][2]]+1;
                    if (!bj[p][q])
                    {
                        j++;
                        d[j][1]=p;
                        d[j][2]=q;
                        bj[p][q]=true;
                    }
                }
            }
        }
        bj[d[i][1]][d[i][2]]=false;
    }
}

bool Bfs(int q)
{
    int i,j,x,y;
    memset(bj,false,sizeof(bj));
    if (l[sx][sy]<q)
        return false;
    d[1][1]=sx;
    d[1][2]=sy;
    bj[sx][sy]=true;
    i=0;
    j=1;
    while (i<j)
    {
        i++;
        for (int k=1;k<=4;k++)
        {
            x=d[i][1]+me[k][1];
            y=d[i][2]+me[k][2];
            if ((x>0)&&(x<n+1)&&(y>0)&&(y<m+1)&&(l[x][y]>=q)&&(!bj[x][y]))
            {
                bj[x][y]=true;
                j++;
                d[j][1]=x;
                d[j][2]=y;
                if ((ex==x)&&(ey==y))
                    return true;
            }
        }
    }
    return false;
}

int FF(int l,int r)
{
    if (l>=r)
        return l;
    int m=(l+r)/2+1;
    if (Bfs(m))
        return FF(m,r);
    else
        return FF(l,m-1);
}

Pascal

uses
    math;

var
    n,m,i,j,k,sx,sy,ex,ey,t:longint;
    l:array [1..500,1..500] of longint;
    d:array [1..1000000,1..2] of longint;
    me:array [1..4,1..2] of longint=((0,1),(1,0),(-1,0),(0,-1));
    bj:array [1..500,1..500] of boolean;
    c:char;

procedure SPFA(j:longint);
var
    i,k,p,q:longint;

begin

    i:=0;
    while i<j do
    begin
        inc(i);
        for k:=1 to 4 do
        begin
            p:=d[i][1]+me[k][1];
            q:=d[i][2]+me[k][2];
            if (p>0) and (p<n+1) and (q>0) and (q<m+1) then
            begin
                if l[d[i][1]][d[i][2]]+1<l[p][q] then
                begin
                    l[p][q]:=l[d[i][1]][d[i][2]]+1;
                    if not bj[p][q] then
                    begin
                        inc(j);
                        d[j][1]:=p;
                        d[j][2]:=q;
                        bj[p][q]:=true;
                    end;
                end;
            end;
        end;
        bj[d[i][1]][d[i][2]]:=false;
    end;

end;

function Bfs(q:longint):boolean;
var
    i,j,k,x,y:longint;

begin

    fillchar(bj,sizeof(bj),false);
    if l[sx][sy]<q then
        exit(false);
    d[1][1]:=sx;
    d[1][2]:=sy;
    bj[sx][sy]:=true;
    i:=0;
    j:=1;
    while i<j do
    begin
        inc(i);
        for k:=1 to 4 do
        begin
            x:=d[i][1]+me[k][1];
            y:=d[i][2]+me[k][2];
            if (x>0) and (x<n+1) and (y>0) and (y<m+1) and (l[x][y]>=q) and (not bj[x][y]) then
            begin
                bj[x][y]:=true;
                inc(j);
                d[j][1]:=x;
                d[j][2]:=y;
                if (ex=x) and (ey=y) then
                    exit(true);
            end;
        end;
    end;
    exit(false);

end;

function find(l,r:longint):longint;
var
    m:longint;

begin

    if l>=r then
        exit(l);
    m:=(l+r) shr 1+1;
    if Bfs(m) then
        exit(find(m,r))
    else
        exit(find(l,m-1));

end;

begin

    assign(input,'init.in');
    reset(input);

    fillchar(l,sizeof(l),$7f);
    readln(n,m);
    for i:=1 to n do
    begin
        for j:=1 to m do
        begin
            read(c);
            case c of
                '+':
                begin
                    inc(t);
                    d[t][1]:=i;
                    d[t][2]:=j;
                    bj[i][j]:=true;
                    l[i][j]:=0;
                end;
                'V':
                begin
                    sx:=i;
                    sy:=j;
                end;
                'J':
                begin
                    ex:=i;
                    ey:=j;
                end;
            end;
        end;
        readln;
    end;
    SPFA(t);
    writeln(find(0,n+m));

end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值