2019牛客暑期多校训练(第八场)D-Distance
膜拜UESTC_Trimen的大佬们~
原题
题意
给定一个n* m* h的空间立方体,进行q次操作。
第1种操作,向空间体中加入一个点(x,y,z)。
第2种操作,找到与(x,y,z)曼哈顿距离最小的点,输出两点间的曼哈顿距离。
思路
BFS。先将n,m,h的中间值换到高的位置,保证h的值小于500,然后将剩下两维压缩处理(不然数组开不下),并且把每层分离出来单独BFS。每加一个点,BFS更新当前平面每个点的最近的点的曼哈顿距离。当查询一个点的时候,遍历所有的高度h,找到三维曼哈顿距离的最小值输出即可。
坑点
要记得把高换为长宽高的中间值,高小了,BFS的平面太大,高大了,遍历的复杂度过高。
(实际上把高换为最小值也能过,时间上也没啥区别。。。)
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100007;
const int INF=1000000007;
const int dx[4]= {0,0,-1,1};
const int dy[4]= {-1,1,0,0};
int n,m,h,q,o;
void trans(int &x, int &y, int &z)
{
if(o==1)
swap(x,z);
if(o==2)
swap(y,z);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&h,&q);
///将h换到中间值,保证h小于500
int a[]={n,m,h};
sort(a,a+3);
if(n==a[1])
o=1;
else if(m==a[1])
o=2;
trans(n,m,h);
int d[500][a[0]*a[2]+1];
///初始化
for(int i=1; i<=h; i++)
for(int j=0; j<n; j++)
for(int k=0; k<m; k++)
d[i][j*m+k]=INF;
for(int i=1,t,x,y,z; i<=q; i++)
{
scanf("%d%d%d%d",&t,&x,&y,&z);
///因为前面长宽高顺序换过了,所以这里的长宽高顺序也要换掉
trans(x, y, z);
x--;
y--;
if (t == 1)
{
queue<int> q;
int s=x*m+y;
d[z][s]=0;
q.push(s);
while(!q.empty())
{
int cur=q.front();
q.pop();
///分离出x0和y0
int x0=cur/m,y0=cur%m;
for(int j=0; j<4; ++j)
{
int x1=x0+dx[j],y1=y0+dy[j];
if(x1>=0&&x1<n&&y1>=0&&y1<m)
{
int nxt=x1*m+y1;
///判断是否需要更新点并且继续找下一个点
if(d[z][cur]+1<d[z][nxt])
{
d[z][nxt]=d[z][cur]+1;
q.push(nxt);
}
}
}
}
}
else
{
int ans=INF;
for(int i=1; i<=h; i++)
ans=min(ans,d[i][x*m+y]+abs(z-i));
printf("%d\n",ans);
}
}
return 0;
}