younik去吃午饭啦

链接:https://ac.nowcoder.com/acm/contest/7031/E
来源:牛客网
 

题目描述

        做完了检查之后,younik得知得要星期天才能拿到结果,于是她离开了校医院。她抬头看了看太阳,感觉自己实在是枵肠辘辘,饥不可堪。Younik早就听说陕西师范大学又叫陕西吃饭大学,她决定去陕师大食堂填饱肚子。

        Younik走到食堂旁边,发现食堂门口居然也在排队(今天怎么到处都在排队),她上前一问,原来为了方便管理,食堂决定,每一个小时才允许大家进去一次,每次吃饭时间必须控制在半个小时以内,还有半个小时要消毒。

        好不容易进入了食堂,younik随便找了个地方坐下。在等饭菜的时候,她发现一件事情:

1.     食堂是长方形的,而且是无限长的(有点奇怪,但是不要在意)。

2.     食堂的中间有一条无限长的平分线,把食堂分成了上下两半(就像是一个x坐标轴,把食堂分成了x为正和x为负)。平分线上可以放高温杀病毒的机器。

        Younik非常好奇这些机器的工作原理,于是她请教了路过她的打饭从不手抖的肖阿姨。打饭从不手抖的肖阿姨说:

1.     每个人坐过的地方都需要消毒。

2.     机器可以清理半径为r的区域的所有病毒。

 

例如:如果有三个人(-2,2),(-2,-1),(2,0)。就需要至少两个机器才能覆盖这三个点,比如图上的两个机器分别放置在-2和1的地方。(机器人的坐标可以是非整数)

       打饭从不手抖的肖阿姨想考考你,你能不能写一个程序,找到覆盖所有人坐过位置的最小数量的高温杀病毒的机器数量。每个人的座位会用x-y坐标表示。

 

输入描述:

 

输入由很多个案例组成,当案例以0 0开头时,表示没有案例了。

每个案例的组成如下:

第一行包含两个整数n (1<=n<=1000)和d(0<d<80),其中n是刚刚前来吃饭的人的数量,d是机器的消毒范围。接下来的n行,每行包含两个整数,代表每个人的坐标位置(坐标的值为整数,y轴的范围是正负200,x轴是正负1000)。

输出描述:

 

每个样例输出一行,表示需要的最小机器数量。

如果无解,则输出-1。

示例1

输入

复制3 1 -1 1 2 1 5 1 3 1 1 2 2 1 5 1 0 0

3 1
-1 1
2 1
5 1
3 1
1 2
2 1
5 1
0 0

输出

复制3 -1

3
-1

原题:poj1328

注意题目是看x轴上的。一样的题在洛谷是雷达安装。

一个座位的最左能到和最右能到的圆心边界点可以通过勾股定理求,然后如果前一个的右界端点>=后一个左界端点,覆盖这两个点的圆的半径<=d就可以满足(画个图可以发现区间∩其实连线长度<三角形最长边的d长度),所以d半径的圆一定满足。然后N^2暴力标记统计就好了。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e3+100;
typedef long long LL;
bool vis[maxn];
LL n,d;
struct P{
	double x,y;
}a[maxn];
struct data{
	double left,right;
}da[maxn];
bool cmp(data A,data B){
	return A.right<B.right;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  while(cin>>n>>d&&n!=0&&d!=0){
  	memset(vis,0,sizeof(vis)); 
  	bool flag=1;
	for(LL i=1;i<=n;i++) {
		cin>>a[i].x>>a[i].y;
		if(a[i].y>d||a[i].y<-d) flag=0;
	}
  	for(LL i=1;i<=n;i++){
  		double mid=sqrt(1.0*d*d-1.0*a[i].y*a[i].y);
		da[i].left=a[i].x-mid;
		da[i].right=a[i].x+mid;  	
	} 
	sort(da+1,da+1+n,cmp);
	LL ans=0;
	for(LL i=1;i<=n;i++){
		if(!vis[i]){
			vis[i]=true;
			for(LL j=i+1;j<=n;j++){
				if(!vis[j]&&da[i].right>=da[j].left){
					vis[j]=true;
				}	
			}
			ans++;
		}
	}
	if(flag)
	cout<<ans<<endl;
	else cout<<-1<<endl;
  }
return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值