UVa 1432 Fire-Control System 解题报告(离散化 + 扫描)

来源:互联网 发布:神经网络算法入门书籍 编辑:程序博客网 时间:2024/05/02 00:16

1432 - Fire-Control System

Time limit: 3.000 seconds

A new mighty weapon has just been developed, which is so powerful that it can attack a sector of indefinite size, as long as the center of the circle containing the sector is the location of the weapon. We are interested in developing a fire-control system that calculates firing-solutions automatically.


The following example gives an example of a firing solution:

\epsfbox{p4356.eps}

Here the firing region is the sector $ \overline{{ABC}}$ that covers six points: A, B, C, D, E, H.

You may further assume that the weapon is always located at point (0, 0), no targets will be on the point (0, 0) and the coordinates of the targets will be distinct.


A firing solution is called effective if and only if it covers a minimum ofK points out of N given points (targets) on the two-dimensional Cartesian plane. Furthermore, since the cost of a particular fire solution is in direct proportion to the size of the area it covers, a firing could be quite costly; thus we are only interested in the optimal firing solution with the minimum cost.

Input 

There are multiple test cases in the input file.

Each test case starts with two non-negative integers, N andK (1$ \le$N$ \le$5000,K$ \le$N), followed byN lines each containing two integers, X, and Y, describing the distinct location of one target. It is guaranteed that the absolute value of any integer does not exceed 1000.

Two successive test cases are separated by a blank line. A case with N = 0 and K = 0 indicates the end of the input file, and should not be processed by your program.

Output 

For each test case, please print the required size (to two decimal places), in the format as indicated in the sample output.

Sample Input 

3 1 0 1 1 0 -5 -6 3 2 0 2 2 0 -5 -6 0 0

Sample Output 

Case #1: 0.00 Case #2: 3.14


    用最小的扇形,覆盖n个点中的k个点。n的范围为5000。

    第一眼看上去不好搞。枚举扇形的左右边界,再让扇形覆盖k个点,复杂度略高( n^3 )。我们可以这样:将每个点到原点的距离离散化,枚举依次枚举该距离为扇形半径。扫描一遍所有点,如果点在这个半径形成的圆内,那么记录这个点的角度。排序角度,统计 i 点 到 i+k-1 点间的角度差,取最小值。以此最小值为扇形的张开角度,更新最小面积即可。注意会有k = 0的情况。代码如下:

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <vector>#include <queue>#include <map>#include <set>#include <string>using namespace std;#define ff(i, n) for(int i=0;i<(n);i++)#define fff(i, n, m) for(int i=(n);i<=(m);i++)#define dff(i, n, m) for(int i=(n);i>=(m);i--)#define mem(a) memset((a), 0, sizeof(a))typedef long long LL;typedef unsigned long long ULL;void work();int main(){#ifdef ACM    freopen("in.txt", "r", stdin);//    freopen("in.txt", "w", stdout);#endif // ACM    work();}/*****************************************/struct Point{    double r, deg;    bool operator<(const Point & cmp) const    {        return deg < cmp.deg;    }} p[5555];const double pi = acos(-1.0);int n, k;double x, y;double rr[5555];double deg[11111];double solve(){    sort(p, p+n);    sort(rr, rr+n);    int m = unique(rr, rr+n)-rr;    double ans = 1e9;    ff(i, m)    {        double maxr = rr[i];        int tot = 0;        ff(j, n) if(p[j].r <= maxr)            deg[tot++] = p[j].deg;        if(tot < k) continue;        ff(j, k)            deg[tot+j] = deg[j] + 2*pi;        double mindeg = 2*pi;        ff(j, tot)            mindeg = min(mindeg, deg[j+k-1] - deg[j]);        ans = min(ans, mindeg*maxr*maxr/2);    }    return ans;}void work(){    int cas = 1;    while(~scanf("%d%d", &n, &k) && (n||k))    {        ff(i, n)        {            scanf("%lf%lf", &x, &y);            rr[i] = p[i].r = sqrt(x*x + y*y);            p[i].deg = acos(x/p[i].r);            if(y < 0) p[i].deg = 2*pi - p[i].deg;        }        double ans = 0;        if(k > 0)            ans = solve();        printf("Case #%d: %.2lf\n", cas++, ans);    }}


0 0
原创粉丝点击