题型:用一个给定半径的圆覆盖最多的点
#include <bits/stdc++.h>
#define PI acos(-1.0)
struct Point{
double x, y;
}pt[2005];
double dis[2005][2005];
struct List{
double a;
bool flag;
int id;
}list[8005];
int cnt;
double Dis(int i, int j){
double dx=pt[i].x-pt[j].x;
double dy=pt[i].y-pt[j].y;
return sqrt(dx*dx+dy*dy);
}
int Cmp(const void*p1, const void*p2){
struct List*a1=(struct List*)p1;
struct List*a2=(struct List*)p2; //角度大的先排,角度同的按ID大的先排
if (a1->a<a2->a)return -1;
else if (a1->a==a2->a) return a1->id-a2->id;
else return 1;
}
int main (void){
int n, i, j, ans, num;
double r, theta, delta, a1, a2;
while (scanf("%d %lf",&n,&r)==2){ //n个点,r为定圆半径
if (n==0&&r==0.0) break;
r=r+0.001;
r=r*2.0;
for (i=1;i<=n;i++)
scanf("%lf %lf", &pt[i].x, &pt[i].y); //PT数组存好各个点
for (i=1;i<n;i++)
for (j=i+1;j<=n;j++){
dis[i][j]=Dis(i, j); //求出任意两点间距离
dis[j][i]=dis[i][j];
}
ans=0;//能覆盖点的总数
for (i=1;i<=n;i++){
cnt=0;
for (j=1;j<=n;j++) //其他点依次扫一次
if ((j!=i)&&(dis[i][j]<=r)){ //两个点可以归入圆里
theta=atan2(pt[j].y-pt[i].y, pt[j].x-pt[i].x);//连线在绝对极坐标系角度
if (theta<0.0) theta=theta+2.0*PI;
delta=acos(dis[i][j]/r); //该点计算圆内临界角度差
a1=theta-delta;
a2=theta+delta;
list[++cnt].a=a1; //存角度
list[cnt].flag=true; //存标志
list[cnt].id=cnt; //存id
list[++cnt].a=a2;
list[cnt].flag=false;
list[cnt].id=cnt;
}
qsort(list+1,cnt,sizeof(struct List),Cmp);
num=0;
for (j=1;j<=cnt;j++)
if (list[j].flag){ //扫一次看被标记的点有少个
num++; //true加false减
if (num>ans) ans=num; //完整循环下来NUM先增后减
} //ANS就是记下其峰值
else num--;
}
//关键说明:以上这个循环模拟的是以一定点在圆上
//圆在旋转A1的角度是表示覆盖该点的有效点,旋转A2的角度是表示不能再覆盖该点
printf("It is possible to cover %d points.\n", ans+1);
}
return 0;
}
覆盖所有点的面积最小值
一、 不能旋转的矩形覆盖所有点:直接找X,Y坐标MAX与MIN值即可
二、 用多边形覆盖所有点:求凸包然后三角剖分求面积
三、 可以旋转的矩形覆盖所有点:求凸包后旋转卡壳找矩形
四、 用圆形覆盖:见模板
定圆盖点
猜你喜欢
转载自blog.csdn.net/cj1064789374/article/details/84933163
今日推荐
周排行