题解 UVA1193 【Radar Installation】

传送门

题意

对于第 ii 组测试数据,在一条数轴上选一些点,用以这些点为圆心作的半径为 dd 的圆覆盖所给点,若无法全部覆盖,则输出 Case i: -1;否则输出 Case i: ++ 最少需要的点数 ansans

分析

为了方便,我们把 xxyy 都存在结构体 asdfasdf 中。

struct asdf
{
	int x,y;
	double l,r;//这个后面会讲
}a[N];

我们首先判断是否能全部覆盖,一个点能够被数轴上的某个点覆盖,当且仅当它与数轴的距离 ai.ya_i.y 不超过半径 dd,所以我们输入的时候判断一下就好了。

t++;//第t组测试数据 
b=0;//b代表是否有点没被覆盖 
for(int i=1;i<=n;i++)
{
	cin>>a[i].x>>a[i].y;
	if(a[i].y>d)//y就是第i个点到数轴的距离
	{
		b=1;//标记 
		break;//已经有不能覆盖的点就不做无用的输入了 
	}
}
if(b)//有没被覆盖的点 
{
	cout<<"Case "<<t<<": -1"<<endl;
	continue;
}

接下来,我们预处理出距离第 ii 个点不超过 dd 的最左点 ai.la_i.l 和最右点 ai.ra_i.r,这样当我们想判断某个点上装的雷达时候能覆盖到第 ii 个点的时候,只要判断是否在 ai.la_i.lai.ra_i.r 的线段上就行了。

那么 ai.la_i.l 怎么求呢?请看下图:

如图所示,dai.yd、a_i.y(ai.xai.l)(a_i.x-a_i.l) 正好构成了一个直角三角形,根据小学时学过的勾股定理

ai.y2+(ai.xai.l)2=d2a_i.y^2+(a_i.x-a_i.l)^2=d^2

反过来就是:

ai.l=ai.xd2+ai.y2a_i.l=a_i.x-\sqrt{d^2+a_i.y^2}

ai.ra_i.r 也同理:

ai.r=ai.x+d2+ai.y2a_i.r=a_i.x+\sqrt{d^2+a_i.y^2}
for(int i=1;i<=n;i++)
{
	a[i].l=a[i].x-sqrt(d*d-a[i].y*a[i].y);
	a[i].r=a[i].x+sqrt(d*d-a[i].y*a[i].y);
}

然后就是贪心了,设上一个雷达的位置为 ww,我们按 xx从小到大排序,当前我们在第 ii 个点,则我们有以下 22 种选择:

1.1. 让当前的点被之前的雷达覆盖。

2.2. 新建一个雷达供它使用。

我们为了使雷达最少,在条件允许的情况下应该尽量选择第一种,条件就是当前雷达位置 ww不少于能覆盖第 ii 个点的最左点 ai.la_i.l,即 w>=ai.lw>=a_i.l,不过有可能当前雷达位置 ww 超过了能覆盖第 ii 个点的最右点 ai.ra_i.r,我们只能把雷达向左移一些满足要求,即 w=min(w,ai.r)w=\min(w,a_i.r)

如果不能选择第一种,那么我们只能选择第二种了,为了给后面留出更多的位置,我们把雷达尽量往右放,又要覆盖这个点,所以只能放在能覆盖第 ii 个点的最右点 ai.ra_i.r,即 w=ai.rw=a_i.r,且 ansans 要加 11,因为我们又放了一个雷达。注意,第一个点时还没有雷达,所以我们在第一个点直接放雷达,然后循环 2n2-n

sort(a+1,a+n+1,cmp);//排序
w=a[1].r;ans=1;//第一个点直接放雷达 
for(int i=2;i<=n;i++)//循环剩下的n-1次 
{
	if(w>=a[i].l)//能覆盖到 
		w=min(w,a[i].r);//第一种选择 
	else 
		ans++,w=a[i].r;//否则只能第二种选择 
}

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int t,n,d,ans;
bool b;
double w;
struct asdf
{
	int x,y;
	double l,r;
}a[N];
bool cmp(asdf p,asdf q)//按x轴从小到大排序 
{
	return p.x<q.x;
}
int main()
{
    while(cin>>n>>d&&n&&d)//有多组数据 
    {
    	t++;//第t组测试数据 
    	b=0;//b代表是否有点没被覆盖 
    	for(int i=1;i<=n;i++)
    	{
    		cin>>a[i].x>>a[i].y;
    		if(a[i].y>d)//y就是第i个点到数轴的距离
    		{
    			b=1;//标记 
    			break;//已经有不能覆盖的点就不做无用的输入了 
			}
		}
		if(b)//有没被覆盖的点 
		{
			cout<<"Case "<<t<<": -1"<<endl;
			continue;
		}
		for(int i=1;i<=n;i++)
		{
			a[i].l=a[i].x-sqrt(d*d-a[i].y*a[i].y);
			a[i].r=a[i].x+sqrt(d*d-a[i].y*a[i].y);
		} 
		sort(a+1,a+n+1,cmp);//排序
		w=a[1].r;ans=1;//第一个点直接放雷达 
		for(int i=2;i<=n;i++)//循环剩下的n-1次 
		{
			if(w>=a[i].l)//能覆盖到 
				w=min(w,a[i].r);//第一种选择 
			else 
				ans++,w=a[i].r;//否则只能第二种选择 
		}
		cout<<"Case "<<t<<": "<<ans<<endl;
	}
	return 0;
}

懂了来领双倍经验

posted @ 2021-02-26 08:15  luckydrawbox  阅读(7)  评论(0)    收藏  举报  来源