LYK快跑!(run)

LYK快跑!(run)
Time Limit:5000ms Memory Limit:64MB

题目描述
LYK陷进了一个迷宫!这个迷宫是网格图形状的。LYK一开始在(1,1)位置,出口在(n,m)。而且这个迷宫里有很多怪兽,若第a行第b列有一个怪兽,且此时LYK处于第c行d列,此时这个怪兽对它的威胁程度为|a-c|+|b-d|。
LYK想找到一条路径,使得它能从(1,1)到达(n,m),且在途中对它威胁程度最小的怪兽的威胁程度尽可能大。
当然若起点或者终点处有怪兽时,无论路径长什么样,威胁程度最小的怪兽始终=0。

输入格式(run.in)
第一行两个数n,m。
接下来n行,每行m个数,如果该数为0,则表示该位置没有怪兽,否则存在怪兽。数据保证至少存在一个怪兽。

输入格式(run.out)
一个数表示答案。

输入样例
3 4
0 1 1 0
0 0 0 0
1 1 1 0

输出样例
1

数据范围
对于20%的数据n=1。
对于40%的数据n<=2。
对于60%的数据n,m<=10。
对于80%的数据n,m<=100。
对于90%的数据n,m<=1000。
对于另外10%的数据n,m<=1000且怪兽数量<=100。


一个很正常的想法:先处理 i,j这个点距离最近怪兽的距离
然后利用这个数组去求答案
我的80代码(处理min1[i][j]复杂度(n*m)^2)

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int inf=1e8;
int min1[1101][1101],cnt;
bool map[1101][1101];
int max1[1101][1101];
struct tt{
    int x,y;
}a[11000000];
struct node{
    int x,y,minm;
};
queue <node> dl;
int n,m;
int dx[]={1,-1,0,0},dy[]={0,0,-1,1};
int bfs()
{
    int ans=0;

    map[1][1]=1;
    node d;
    d.x=1,d.y=1,d.minm=min1[1][1];
    dl.push(d);
    while(!dl.empty())
    {
        d=dl.front();
        dl.pop();
        //printf("%d %d %d\n",d.x,d.y,d.minm);
        for(int i=0;i<=3;i++)
        {
            int xx=d.x+dx[i],yy=d.y+dy[i];
            if(xx<1||xx>n||yy<1||yy>m) continue;
            if(xx==n&&yy==m)
            {
                ans=max(ans,min(min1[n][m],d.minm));
                continue;
            }
            int minf=min(d.minm,min1[xx][yy]);
            if(minf>max1[xx][yy])
             max1[xx][yy]=minf,dl.push((node){xx,yy,minf});
        }
    }

    return ans;
}
int abs(int x)
{
    if(x<0) return -x;
    return x;
}
int main()
{
    freopen("run.in","r",stdin);
    //freopen("run.out","w",stdout);
    scanf("%d%d",&n,&m);

    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      {
        scanf("%d",&map[i][j]);
        if(map[i][j]) a[++cnt].x=i,a[cnt].y=j;
      }
      printf("%d\n",cnt);
    if(map[1][1]||map[n][m])
     {
        printf("0");
        return 0;
     } 

     for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
      {
        if(map[i][j]) 
         continue;
        min1[i][j]=inf;
        for(int k=1;k<=cnt;k++)
         min1[i][j]=min(min1[i][j],abs(i-a[k].x)+abs(j-a[k].y));
      } 
    /*for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      printf("%d ",min1[i][j]);*/ 

    /*for(int i=1;i<=cnt;i++)
     printf("%d %d\n",a[i].x,a[i].y);*/
     //bfs();
    printf("%d",bfs());
}

正解:二分+BFS
处理min数组时,应该用最近的怪兽拓展,类似于最短路,用BFS实现(O(n*m))

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int min1[1101][1101],cnt;
bool map[1101][1101];
struct node{
    int x,y;
};
int n,m;
int dx[]={1,-1,0,0},dy[]={0,0,-1,1};
bool check(int mid)
{   
    queue <node> dl;
    memset(map,0,sizeof(map));

    map[1][1]=1;
    node d;
    d.x=1,d.y=1;
    dl.push(d);
    while(!dl.empty())
    {
        d=dl.front();
        if(d.x==n&&d.y==m) return 1;
        dl.pop();
        //printf("%d %d %d\n",d.x,d.y,d.minm);
        for(int i=0;i<=3;i++)
        {
            int xx=d.x+dx[i],yy=d.y+dy[i];
            if(xx<1||xx>n||yy<1||yy>m) continue;
            if(min1[xx][yy]>=mid&&!map[xx][yy])
             map[xx][yy]=1,dl.push((node){xx,yy});
        }
    }

    return 0;
}
int abs(int x)
{
    if(x<0) return -x;
    return x;
}
int main()
{
    freopen("run.in","r",stdin);
    freopen("run.out","w",stdout);
    scanf("%d%d",&n,&m);
    queue <node> dl;
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      {
        scanf("%d",&map[i][j]);
        if(map[i][j]) dl.push((node){i,j}),min1[i][j]=1;//为了好拓展最小值,不发生冲突,输出时答案-1即可
      }
      //printf("%d\n",cnt);
    if(map[1][1]||map[n][m])
     {
        printf("0");
        return 0;
     } 
     while(!dl.empty())
     {
        node d=dl.front();
        dl.pop();
        for(int i=0;i<=3;i++)
        {
            int xx=d.x+dx[i],yy=d.y+dy[i];
            if(xx<1||xx>n||yy<1||yy>m) continue;
            if(!min1[xx][yy]) min1[xx][yy]=min1[d.x][d.y]+1,dl.push((node){xx,yy});
        }
     }
    /*for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      printf("%d ",min1[i][j]);*/ 

    /*for(int i=1;i<=cnt;i++)
     printf("%d %d\n",a[i].x,a[i].y);*/
     //bfs();
     int l=0,r=min(min1[1][1],min1[n][m]);
     while(l<=r)
     {
        int mid=(l+r)/2;
        if(check(mid)) l=mid+1;
        else r=mid-1;
     }

     printf("%d",r-1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值