【2019百度之星初赛一C题 HDU 6670 --- Mindis】
共 4178字,需浏览 9分钟
·
2021-05-02 13:53
【2019百度之星初赛一C题 HDU 6670 --- Mindis】
Description
平面上有 n 个矩形,矩形的边平行于坐标轴,现在度度熊需要操控一名角色从 A 点走到 B 点。
该角色可以上下左右移动,在恰被 k 个矩形覆盖的区域,该角色的速率为 k+1 个距离/秒(矩形覆盖区域包括边界)。
请求出 A 移动到 B 最快需要多少秒。
Input
第一行一个整数 T (1≤T≤5) 表示数据组数。
对于每组数据,第一行输入一个整数 n (1≤n≤200)。
接下来 n 行每行 4 个整数 x1,y1,x2,y2 (0≤x1<x2≤1000000000,0≤y1<y2≤1000000000),分别表示矩形的左下角和右上角的坐标。
最后一行四个整数 xa,ya,xb,yb ((0≤xa,xb,ya,yb≤1000000000) 代表 A 和 B 的坐标。
Output
对于每组数据,输出一个小数表示答案。答案保留 5 位小数。
Sample Input
1
1
5 5 6 6
7 7 8 8
Sample Output
2.00000
解题思路
由于本题中x,y的取值范围可以达到1000000000,并且n<=200,所以我们可以使用区间离散化的思想去做这个题。
将所有坐标离散化,建网格图(400*400)。
下面我们就需要统计每个点被多少个矩形覆盖,通过num1[][],num2[][]两个数组分别记录垂直方向和水平方向上每个顶点被矩形覆盖的距离(最右端的不记录,减少后面的判断)(我写的可能不是特别清楚,可以根据代码理解下)。
然后bfs跑一遍就行了。
注意:这个题比较特殊,不是简单的bfs找打点就break,这个题找到点时可能时间也不一定是最短的,所以需要全部跑完。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define MAXN 410
#define INF 0x3f3f3f3f
int p[MAXN][4],dx[MAXN],dy[MAXN],num1[MAXN][MAXN],num2[MAXN][MAXN];
int begin_x,begin_y,end_x,end_y;
double dis[MAXN][MAXN];
bool vis[MAXN][MAXN];
int dir[4][2]={1,0,-1,0,0,-1,0,1};
int nx,ny;
struct Node
{
int x,y;
bool operator<(const Node &a) const
{
return dis[x][y]>=dis[a.x][a.y];
}
};
void fun()
{
dis[begin_x][begin_y]=0;
priority_queue<Node,vector<Node>,less<Node> > que;
Node node;
node.x=begin_x;
node.y=begin_y;
que.push(node);
int x,y,xx,yy;
while(!que.empty())
{
Node nn = que.top();
que.pop();
x=nn.x;
y=nn.y;
if(vis[x][y])
continue;
vis[x][y]=true;
for(int i=0;i<4;++i)
{
xx=x+dir[i][0];
yy=y+dir[i][1];
if(!xx||!yy||xx>nx||yy>ny||vis[xx][yy])
continue;
double d;
if(x==xx)//相信大家之前没怎么理解num1和num2数组,现在看下面就明白了,
在垂直方向移动时只需要根据左侧端点进行计算,右侧可能没有被相同的矩形数覆盖。
d=1.0*(dy[y]-dy[yy])/num1[x][min(y,yy)];
else//同理,水平方向也存在这种情况。
d=1.0*(dx[x]-dx[xx])/num2[min(x,xx)][y];
if(d<0)
d=-d;
if(dis[x][y]+d<dis[xx][yy])
{
dis[xx][yy]=dis[x][y]+d;
nn.x=xx;
nn.y=yy;
que.push(nn);
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
nx=0,ny=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=0;j<4;++j)
scanf("%d",&p[i][j]);
dx[++nx]=p[i][0],dx[++nx]=p[i][2];
dy[++ny]=p[i][1],dy[++ny]=p[i][3];
}
scanf("%d%d%d%d",&begin_x,&begin_y,&end_x,&end_y);
dx[++nx]=begin_x;dx[++nx]=end_x;
dy[++ny]=begin_y;dy[++ny]=end_y;
sort(dx+1,dx+nx+1);
sort(dy+1,dy+ny+1);
nx = unique(dx+1,dx+nx+1)-dx-1;
ny = unique(dy+1,dy+ny+1)-dy-1;
for(int i=1;i<=nx;i++)
for(int j=1;j<=ny;j++)
num1[i][j]=num2[i][j]=1;//初始化为1
for(int i=1;i<=n;i++)
{
p[i][0]=lower_bound(dx+1,dx+1+nx,p[i][0])-dx;
p[i][1]=lower_bound(dy+1,dy+1+ny,p[i][1])-dy;
p[i][2]=lower_bound(dx+1,dx+1+nx,p[i][2])-dx;
p[i][3]=lower_bound(dy+1,dy+1+ny,p[i][3])-dy;
for(int j=p[i][0];j<=p[i][2];++j)//记录垂直方向矩形覆盖次数+1
for(int k=p[i][1];k<p[i][3];++k)
num1[j][k]++;
for(int j=p[i][0];j<p[i][2];++j)//记录水平方向矩形覆盖次数+1
for(int k=p[i][1];k<=p[i][3];++k)
num2[j][k]++;
}
for(int i = 1;i <= nx;i++)
for(int j = 1;j <= ny;j++)
dis[i][j] = INF, vis[i][j] = false;
begin_x = lower_bound(dx+1,dx+1+nx,begin_x) - dx;
begin_y = lower_bound(dy+1,dy+1+ny,begin_y) - dy;
end_x = lower_bound(dx+1,dx+1+nx,end_x) - dx;
end_y = lower_bound(dy+1,dy+1+ny,end_y) - dy;
dis[begin_x][begin_y]=0;
fun();
printf("%.5lf\n",dis[end_x][end_y]);
}
return 0;
}