UVaLive LA 4356 - Fire-Control System (扫描法 思维)

Time Limit:3000MS Memory Limit:Unknown 64bit IO Format:%lld & %llu

[]  [Go Back]  [Status]  

Description

Download as PDF


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 of K 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 and K(1$ \le$N$ \le$5000, K$ \le$N) , followed by N 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个点,求以(0,0)为圆心至少包含k个点的扇形的最小面积


思路:

容易想到的是 先枚举半径r,然后扫描一下包含k个点的最小扇形面积 

扫描最小扇形面积和扫描长度为k的最小子序列和差不多,要注意的是因为是循环,所以扫描的时候要扩成两倍 扫描保证长度不超过n


问题:

遇到的问题真是多啊 WA了无数多次

首先就是忘了考虑循环问题,没有扩为两倍

然后扩为两倍后的角度问题,先是改为 if (终点j>=n) angle += 2*PI 但是有个样例有错(因为其他错误)

然后没有细想改为 if (角度angle<eps) angle += 2*PI 样例过了 但是WA

后来继续对拍 发现:目标要求覆盖两个点 如果两个点在一条线上  结果应该是0 因为角度angle=0 但是我angle<eps angle+=2*PI 然后改为之前的 if (终点j>=n) angle += 2*PI 然后发现了是tp[j]  tp[stj]写成了j stj


样例:

<span style="color:#000000;">6 2
-10 0
3 -3
0 -2
-9 10
0 -1
-10 2
Case #1: 0.00
2 2
-1 -1
-1 1
Case #2: 1.57
5 5
4 -7
-7 0
3 2
10 -7
-8 0
Case #3: 277.85 </span>



#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>

using namespace std;

//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif

#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)

const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const double PI = (4.0*atan(1.0));

struct Point {
    double x, y;
    double ang, r;
    void set(int xx, int yy) {
        x = xx;
        y = yy;
        ang = atan2(y, x);
        r = sqrt(x*x + y*y);
    }
    bool operator < (const Point & b) const {      
        return ang < b.ang;
    }
};


const int maxn = 5000 + 20;
int n, K;
Point points[maxn*2];
int tp[maxn*2];
double R[maxn];
int RN[maxn];

int main() {
    int kase = 1;
    
    while(scanf("%d%d", &n, &K) != EOF && !(!n && !K)) {
        for(int i=0; i<n; i++) {
            double x, y;
            scanf("%lf%lf", &x, &y);
            points[i].set(x, y);
            R[i] = points[i].r;
        }
        if(K <= 1) {
            printf("Case #%d: 0.00\n", kase++);
            continue;
        }
        sort(points, points+n);
        for(int i=n; i<2*n; i++) {
            points[i] = points[i-n];
        }
        sort(R, R+n);
        int num = 0;
        RN[0] = 1;
        for(int i=1; i<n; i++) {
            if(fabs(R[i] - R[i-1]) > eps) {
                R[++num] = R[i];
                RN[num] = 1;
            } else {
                RN[num]++;
            }
        }
        double ans = INF;
        for(int i=0; i<=num; i++) {
            double r = R[i];
            int stj, tNum=0;
            int tnum = 0;
            for(int j=0; j<2*n; j++) if(points[j].r < r + eps) {
                tp[tnum++] = j;
            }
            for(int j=0; j<tnum; j++) {
                tNum++;
                if(tNum == 1) {
                    stj = j;
                    continue;
                }
                while(tNum >= K) {
                    if(tp[j] - tp[stj] + 1 > n) {
                        stj++;
                        tNum--;
                        continue;
                    }
                    double angle = points[tp[j]].ang - points[tp[stj]].ang;
                    if(tp[j] >= n) angle += 2*PI;
                    double tArea = angle * r * r / 2.0;
                    if(tArea < ans) {
                        ans = tArea;
                    }
                    stj++;
                    tNum--;
                }
            }
        }
        printf("Case #%d: %.2lf\n", kase++, ans);
    }

    return 0;
}



附上数据生成器和对拍工具

数据生成器

#!/usr/bin/env python
# coding=utf-8
import random
T = random.randint(4, 10)
res = ""
for ii in range(0, T):
    n = random.randint(1, 6)
    m = random.randint(1, n)
    res += str(n) + ' ' + str(m) + '\n';
    for i in range(0, n):
        x = random.randint(-10, 10)
        y = random.randint(-10, 10)
        res += str(x) + ' ' + str(y) + '\n'
res += '0 0\n'
f = file("data.in", "w")
f.write(res)
f.close()


对拍

#!/bin/bash
while true; do
    python ./py.py
    ./LA4356 < data.in > output.a
    ./test < data.in > output.b
    diff output.a output.b
    if [ $? -ne 0 ] ; then break; fi
done







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值