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);
}