HDU 6670 坐标离散化 最短路

平面上有 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

思路:第一步肯定是将有用的坐标离散化,  x1,y1,x2,y2 sx,sy,ex,ey这些有用的坐标肯定都要离散化(有些题目可能有些有用的坐标忘记离散化了,离散化的时候要想一下哪些坐标有用)  离散化后然后就讨论怎么加矩形覆盖,这样加更方便既:在加一个x1,x2,y1,y2的矩形的时候用一个sumx[x][y]记录  x1 y1 ,x2-1  y2 的矩形,既最右边那一行没有加;同理sumy记录的一个矩形最上面那一行没有加,这样在处理速度的时候特别方便(具体看代码);然后相邻的点建边跑最短路即可,但是要注意一点  不能用vis标记已经访问过的点    以前跑最短路的时候第一次出来的权值一定是最小的,后面出来肯定最大,但是这个题目不一样;

 

#include<bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<LL,LL>P;
const int len=5e2+9;
const LL mod=998244353;
int a[len],b[len],x1[len],x2[len],y11[len],y2[len];
int tota,totb,sx,sy,ex,ey;
int getx(int x){return lower_bound(a+1,a+1+tota,x)-a;}
int gety(int x){return lower_bound(b+1,b+1+totb,x)-b;}
double numx[len][len],numy[len][len],dis[len][len];
struct Node{
	int x,y;
	bool operator<(const Node a)const
	{return dis[x][y]>=dis[a.x][a.y];}
};
int dx[]={0,0,-1,1};
int dy[]={1,-1,0,0};
void bfs()
{
	for(int i=1;i<=tota;++i)
		for(int j=1;j<=totb;++j)
			dis[i][j]=1e18;
	priority_queue<Node,vector<Node>,less<Node> >qu;
	qu.push({sx,sy});
	dis[sx][sy]=0;
	while(qu.size())
	{
		Node p=qu.top();qu.pop();
		for(int i=0;i<4;++i)
		{
			int xx=p.x+dx[i];
			int yy=p.y+dy[i];
			if(xx<=0||xx>tota||yy<=0||yy>totb)continue;
			double w;
			if(xx==p.x)w=fabs(b[p.y]-b[yy])/numy[xx][min(p.y,yy)];
			else w=fabs(a[p.x]-a[xx])/numx[min(xx,p.x)][p.y];
			if(dis[p.x][p.y]+w<dis[xx][yy])
			{
				dis[xx][yy]=w+dis[p.x][p.y];
				qu.push({xx,yy});
			}
		}
	}
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		tota=totb=0;
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;++i)
		{
			scanf("%d%d%d%d",&x1[i],&y11[i],&x2[i],&y2[i]);
			a[++tota]=x1[i];
			a[++tota]=x2[i];
			b[++totb]=y11[i];
			b[++totb]=y2[i];
		}
		scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
		a[++tota]=sx;b[++totb]=sy;
		a[++tota]=ex;b[++totb]=ey;
		sort(a+1,a+1+tota);
		sort(b+1,b+1+totb);
		tota=unique(a+1,a+1+tota)-a-1;
		totb=unique(b+1,b+1+totb)-b-1;
		sx=getx(sx);sy=gety(sy);
		ex=getx(ex);ey=gety(ey);
		for(int i=1;i<=tota;++i)
			for(int j=1;j<=totb;++j)
				numx[i][j]=numy[i][j]=1;
		for(int i=1;i<=n;++i)
		{
			x1[i]=getx(x1[i]);
			x2[i]=getx(x2[i]);
			y11[i]=gety(y11[i]);
			y2[i]=gety(y2[i]);
			for(int j=x1[i];j<x2[i];++j)
				for(int k=y11[i];k<=y2[i];++k)
					numx[j][k]++;	
			for(int j=x1[i];j<=x2[i];++j)
				for(int k=y11[i];k<y2[i];++k)
					numy[j][k]++;
		}
		bfs();
		printf("%.5lf\n",dis[ex][ey]); 
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值