poj138——建立雷达,贪心,求线段交集

时间:2020-11-21
本文章向大家介绍poj138——建立雷达,贪心,求线段交集,主要包括poj138——建立雷达,贪心,求线段交集使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

​ 本题的一个重要转化是:将每小岛的位置转换成一个线段,然后求能够使得每个线段上都有一个点的情况下,需要的点的最小个数。因为有重叠部分的线段只需要一个点就可以,所以重点在于求线段的交集

​ 对于一组线段组成的集合,当且仅当 这个集合中最大的左端点小于最小的右端点的时候,这一组线段集合才会都重叠。

#include<iostream>
#include<algorithm>
#include<cstring>  
#include<cmath>
using namespace std;
const int MAX = 1010;
int n, d;
int tot = 1;
struct Node{
	double left;
	double right;
};

Node a[MAX];

bool cmp(const Node& a, const Node& b)
{
	return a.left < b.left;
}

void solve()
{
	// 按左端点从小到大排序 
	sort(a, a+n, cmp);
	// 遍历 
	int ans = 1;
	double now_right = a[0].right;
	for (int i = 1; i < n; ++i) {
		//所有线段的交集就是最大的左端点小于最小的右端点 
		// 如果现在的左端点小于等于现存集合中线段的最小右端点,说明这个集合可以加入这个线段 
		if (a[i].left <= now_right) {
			now_right = min(now_right, a[i].right);
		}
		//  如果现在的集合不能加入这个线段,那么就新开一个集合,其最小右端点就是该线段的右端点 
		else {
			ans++;
			now_right = a[i].right;
		} 
	} 
	cout << "Case " << tot << ": " << ans << endl;
	tot++;
} 

int main()
{

	while(cin >> n >> d) {
		bool flag = true;
		if (n == 0 && d == 0) break;
		for (int i = 0; i < n; ++i) {
			int x, y;
			cin >> x >> y;
			// 如果坐标y大于d,那么无解 
			if (y > d) {
				flag = false;
			}
			// 计算能够覆盖该点的圆心所在的线段 
			a[i].left  = (double)x - sqrt((double)d*d - (double)y*y); 
			a[i].right = (double)x + sqrt((double)d*d - (double)y*y); 
		} 
		
		// 有解的话就solve 
		if (flag) solve();
		// 无解就直接print -1 
		else {
			cout << "Case "<< tot << ": "<< -1 << endl;
			tot++;
		} 
	}
	return 0; 
}

原文地址:https://www.cnblogs.com/VanHa0101/p/14017646.html