最大不相交子集 POJ1328

先解释一下最大不相交子集:
设有许多集合[Ai,Bi];
最大不相交子集: 所有集合相交,产生的子集,这些产生的子集中的任意两个子集相交都为空集,产生的子集一定是最大的。

算法框架:

for (int i ;i < n ;i++) {
   if (子集i的左边 > 子集j的右边 (i > j) ) {
    		最大不相交子集个数加一;
    		将j变为i;
       }
 }
 最大不相交子集个数加一;

例题: POJ 1328
题目大意与基本:
设海岸线是一条无限长的直线,一边是陆地一边是海洋,海洋中有一些小岛,每个小岛可以看作一个点,要在海岸线上安装一些雷达,每个雷达只能覆盖半径为d的圆形区域。海洋中的某个小岛能够被雷达覆盖到,当且仅当它和某个雷达之间的距离小于或者等于d。将海岸线定义为x轴,海洋在x轴上部,陆地在x轴下部,给定海洋中各个小岛的坐标位置(x,y),和雷达覆盖半径d,求覆盖所有小岛至少需要安装多少个雷达?
输入输入包含多组测试数据。每组测试数据的第一行包含两个整数 n (1<=n<=1000) 和d,分别表示海中的小岛数量和每个雷达的信号覆盖半径。接下来的n行,每一行包含两个整数,表示每个小岛的坐标。每组测试数据之间以一个空行间隔。当n=d=0时表示输入结束。
输出对每组测试数据输出一行,包含每组测试数据的编号,以及对应的最少需要安装多少雷达。如果不管安装多少雷达,信号都无法覆盖所有的小岛,输出-1。
思路:简单贪心。以每个小岛为圆心作以半径为d的圆,找出与X轴相交的区间,意思为在这个区间上的任意一点都可以作为圆心,包含这个小岛。 这时就需要把所有小岛的在X轴的区间找到。 有交集的部分说明可以用一个圆覆盖。这是算出最小的圆,先排序,排序之后找到最左边小岛的的右区间,然后看每一个小岛的左区间是否比右区间小,如果小的话,说明有交集,就可以用一个圆来覆盖。这样就将问题转换成了最大不相交区间集问题。

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//结构体,left:圆与x轴的左交点 right:圆与x的右交点
//重载小于运算符,  用于排序
struct Node{
	double left, right;
	bool operator < (const Node& t1)const {
		return this->right < t1.right;
	}
};

//主函数
int main() {
	//t:样例数
	//n:岛屿个数
	//d:雷达扫描半径
	//nums:最少雷达数
	int t = 0,n,d,nums;

	//岛屿(x,y)的坐标
	int x[1000], y[1000];
	//结构体数组
	Node out[1000];
	//标志位,  true:有结果; false:没结果,输出“-1”;
	bool fl = true;

	//处理。
	//输入n,d; “0 0”则结束循环
	while (cin >> n >> d && n) {
		//初始化
		nums = 0;
		fl = true;

		//输入岛屿(x,y)的坐标
		for (int i = 0; i < n; i++) {
			cin >> x[i] >> y[i];
		}

		//用数学公式求岛屿与x轴的两个交点“ x = ((-b) +or- 根号(b * b - 4 * a * c)) / 2"
		for (int i = 0; i < n; i++) {
			double a, b, c;
			a = 1;
			b = - 2 * x[i];
			c = x[i] * x[i] + y[i] * y[i] - d * d;

			if (b * b - 4 * a * c < 0 || d < 0 || y < 0) {
				fl = false;
				continue;
			}
			out[i].left = (-b - sqrt(b * b - 4 * a * c)) / 2 * a;
			out[i].right = (-b + sqrt(b * b - 4 * a * c)) / 2 * a;

			if (out[i].left > out[i].right) {
				swap(out[i].left, out[i].right);
			}
		}
		//for (int i = 0; i < n; i++) {
		//	cout << out[i].left << "  " << out[i].right << endl;
		//}
		if (!fl) {
			printf("Case %d: %d\n", ++t, -1);
			continue;
		}

		//排序
		sort(out, out + n);
		int j = 0;

		//求最大且不相交的子集,      
		for (int i = 1; i < n; i++) {
			if (out[i].left > out[j].right) {
				++nums;
				j = i;
			}
		}
		printf("Case %d: %d\n", ++t, nums + 1);
	}
}

最大不相交子集:

//求最大且不相交的子集,      
	for (int i = 1; i < n; i++) {
		if (out[i].left > out[j].right) {
			++nums;
			j = i;
		}
	}

你可能感兴趣的:(最大不相交子集 POJ1328)