算法书上区间选点的问题,是一个很基础的贪心算法:给定n个区间,要求每个区间至少有一个点,那么所选点数最少为多少?
依照题目的意思,这些区间肯定是有相交的部分,那么区间问题先按照左端点或者右端点排序,这里为了方便,利用左端点由大到小排序,当下一个区间的左端点在上一区间的右端点左边的时候,即有公共部分,那么直接选取上一个区间的右端点为所选点,另外,如果整下一个区间都在上一个区间内(区间包含的情况),即x1<x2<y2<=y1,那么直接将y2的值来更新。这个贪心策略其实是选择右端点是最明智的,因为它比前面的点覆盖范围更大。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int x;
int y;
}a[10009];
int cmp(node a,node b)
{
return a.x<b.x;//按x由小到大排序
}
int main()
{
int ans,n,l,r,i;
scanf("%d",&n);
for(i=0;i<=n-1;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
}
sort(a,a+n,cmp);
ans=1;
l=a[0].x;
r=a[0].y;
for(i=1;i<=n-1;i++)
{
if(a[i].x<=r)
{
if(a[i].y<r)
{
r=a[i].y;
}
}
else
{
ans++;
r=a[i].y;
}
}
printf("%d\n",ans);
}
Uvalive2519
题目大意:给出 n 和半径 r, 然后给出 n 个坐标, 现在要求在 x 轴选出最少的点, 以这些点为圆心, 半径为 r 画圆, 要求将所有点均在画的圆内
分析题目:从这一点坐标为圆心画圆,交于x轴的部分即为区间,那么就很好处理了,直接按照上一题的模板,稍稍处理一下就可以了,当y>r是,无论怎么画圆都不会和x轴有交点输出-1即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
struct node
{
double x;
double y;
} a[20009];
int cmp(node a,node b)
{
return a.x<b.x;
}
int Count=1;
int main()
{
int n,i;
double r,x,y;
while(~scanf("%d%lf",&n,&r))
{
if(n==0) break;
int flag=1;
for(i=0; i<=n-1; i++)
{
scanf("%lf%lf",&x,&y);
if(fabs(y)>r)
{
flag=-1;
continue;
}
double d=sqrt(r*r-y*y);
a[i].x=x-d;
a[i].y=x+d;
}
if(flag==-1) printf("Case %d: -1\n",Count++);
else
{
sort(a,a+n,cmp);
int ans=1;
r=a[0].y;
for(i=1; i<=n-1; i++)
{
if(a[i].x<=r)
{
if(a[i].y<r)
{
r=a[i].y;
}
}
else
{
ans++;
r=a[i].y;
}
}
printf("Case %d: %d\n",Count++,ans);
}
}
}