【2019百度之星初赛一C题 HDU 6670 --- Mindis】

【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,这个题找到点时可能时间也不一定是最短的,所以需要全部跑完。

AC代码:

#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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值