LA 4356 Fire-Control System (扫描法)

来源:互联网 发布:碳纤维管取暖器 知乎 编辑:程序博客网 时间:2024/05/21 09:31

LA 4356 Fire-Control System

题目大意:

平面上有n个点,找到一个以(0,0)为圆心的扇形,至少覆盖k个点,使其面积尽可能小.

题目分析:

影响扇形面积的有两个因素:圆心角和半径,但是并不容易同时维护两个变量.
可以选择确定某一变量,使得另一变量尽可能小来使得面积尽可能小.
这里选择先确定半径,那么就会剩下一些点,再在这些点中筛选使其面积尽可能小.

代码:

#include<cmath>#include<cstdio>#include<iostream>#include<algorithm>using namespace std;const double PI=acos(-1.0);const int maxn=5000+10;struct Point {    double k;//(x,y)与(0,0)所成弧度角     int x,y,r2;//r2=r*r=x*x+y*y     bool operator < (const Point& rhs) const {        return k<rhs.k;    }    void input() {        scanf("%d%d",&x,&y);        k=atan2(y,x);r2=x*x+y*y;    }}P[maxn];double A[maxn];//存放筛出来的点的角度 int vis[2000010],n,k,kase;//vis判断当前枚举的R2是否已经枚举过了 double solve(){    if(k==0) return 0;    double ans=1e9;    for(int i=0;i<n;i++) {        int cnt=0,R2=P[i].r2;        if(vis[R2]==kase) continue; vis[R2]=kase;//若当前已经算过了,就不用再算         for(int j=0;j<n;j++) if(P[j].r2<=R2) A[cnt++]=P[j].k;//若能被包括,将其角度放进A中         if(cnt<k) continue;        for(int j=0;j<cnt;j++) {//因为只要k个就满足了,对于某个确定起点j,从j开始逆时针转动,             double now;//当找到k个点时,一定是以j为起点的最小角度,所以对于每个起点j,只需要知道j往后k个的角度             if(j+k-1<cnt) now=A[j+k-1]-A[j];            else now=A[k-(cnt-j)-1]+2*PI-A[j];//若往后又到了开始,要+2π             ans=min(ans,R2*now/2);        }    }    return ans;}int main(){    while(scanf("%d%d",&n,&k)==2&&(n||k)) {        for(int i=0;i<n;i++) P[i].input();        if(k) sort(P,P+n); ++kase;        printf("Case #%d: %.2lf\n",kase,solve());    }    return 0;}
0 0
原创粉丝点击