POJ1328-贪心-区间选点问题

/*转载请注明出处:乄心-小黄豆http://blog.csdn.net/wuxinxiaohuangdou*/

题目大意:在x轴上建立尽量少的雷达覆盖所有的岛屿。

Input:岛屿的数量n,雷达覆盖半径d.接下来的n行一行表示一个岛屿(x,y).

 Output:每个案例的雷达最少数目.

经典的区间选点!

要搞清楚为什么排序,然后要明白如何选点。

思想(排序原因):小区间被满足,大区间一定被满足。

(所以排序后所有岛屿都是 递增的!)(即小区间都在前面。)

 选点:只有前一个点的右端点小于下一个点的左端点,这时才选一个点(即增加一个雷达)因为不可能存在一个雷达可以覆盖到这两个岛屿,而且此时前面用一个雷达覆盖即为最优解!(因为大区间包含了小区间)

 

/*63MS    区间选点问题!*/
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
double d;
int num=1;
class Node
{
public:
	double x,y;        //点坐标
	double left,right; //在x轴上雷达能够覆盖到该点的范围。
	double qu_lenth;   //该范围长度。
	bool operator<(const  Node& t) const
	{
		if(right!=t.right)
			return right<t.right;    //(右端点不等时)把右端点从小到大排序。 
		else
			return qu_lenth<t.qu_lenth; //否则把长度从小到大排序。
	}
}a[1010];
double right_dis(double x0,double y0)  //计算右端点
{
	double x=sqrt(d*d-y0*y0)+x0;
	return x;
}
double left_dis(double x0,double y0)  //计算左端点
{
	double x=-sqrt(d*d-y0*y0)+x0;
	return x;
}
int main()
{
	int i;
	while(true)
	{
		int ok=1;
		int count=1;
		cin>>n>>d;
		if(n==0&&d==0) break;
		if(n==0||d==0)        //岛数为0,或雷达半径为0,都直接输出-1.
		{
			cout<<"Case "<<num++<<": -1"<<endl;
			continue;
		}
		for(i=1;i<=n;i++)
		{
			cin>>a[i].x>>a[i].y;
			if(a[i].y>d) //如果某个岛的垂直距离(即y)大于雷达的覆盖半径,那么肯定无解,直接在后输出-1。
			{
				ok=0;
			}
			a[i].right=right_dis(a[i].x,a[i].y);  //得到每个岛的数据。
			a[i].left=left_dis(a[i].x,a[i].y);
			a[i].qu_lenth=fabs(a[i].right-a[i].left);
			//cout<<"a[i].right="<<a[i].right<<" "<<"a[i].left="<<a[i].left<<endl;
		}
		if(ok==0) 
		{
			cout<<"Case "<<num++<<": -1"<<endl;
			continue;
		}
		sort(a+1,a+n+1);  //给岛(相当于区间的点)进行排序.
		double temp;
		temp=a[1].right;  //从第一个岛的右端点开始。
		for(i=2;i<=n;i++) //枚举到最后个岛
		{
			if(temp<a[i].left) //一旦前面一个岛的右端点小于后一个岛的左端点.
			{
				temp=a[i].right;  //就把这个岛的右端点给temp。
				count++;          //这个时候雷达的数量就加1。
			}
		}
		cout<<"Case "<<num++<<": "<<count<<endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值