题意:
一个直角座标系,x轴上方有N个点。
现要求画若干个圆心在x轴上,半径为R的圆,将N个点包含(内部或边界)
输入最小的圆的数量。
不存在则输出-1
思路:
对于每个点分析,如纵座标大于R则不存在可行方案
否则在x轴上存在一区间上所有点皆符合条件(点间距小于或等于R)
子问题:线性区间选点
给定n个区间,要求选若干个点,保证每个区间内都有点被选,输出点的最小数目
子问题思路:
将区间按照右边界升序排序,相同右边界也按升序排序。
每次选取当前区间最右点。然后跳过左边界小于此点的区间继续计数即可。
贪心思路证明:
对于当前区间选取中间某一点,同时影响了m个区间
将此点移动到本区间末,影响区间数目不会减小,甚至有可能影响更多的区间。
#include <stdio.h>
#include <algorithm>
#define LL long long
using namespace std;
struct aa
{
int l;
int r;
};
aa area[101000];
bool cmp(const aa &a, const aa &b)
{
if(a.r!=b.r)
return a.r < b.r;
return a.l < b.l;
}
int main()
{
int n, r;
int case_num = 1;
while(scanf("%d %d", &n, &r)==2 && (n||r))
{
int flag = 0;
for (int i = 0; i < n; i++)
{
int x, y;
scanf("%d %d", &x, &y);
if(y > r)
{
flag = 1;
continue;
}
int diff = 0;
for(; ;diff++)
if(((LL)diff*diff + (LL)y*y) > (LL)r*r)
break;
diff--;
area[i].l = x-diff;
area[i].r = x+diff;
}
if(flag)
{
printf("Case %d: -1\n", case_num++);
continue;
}
sort(area, area + n, cmp);
int res = 1;
int right = area[0].r;
for (int i = 1; i < n; ++i)
{
if(area[i].l>right)
{
res++;
right = area[i].r;
}
}
printf("Case %d: %d\n", case_num++, res);
}
}
WA