Time Limit:3000MS | Memory Limit:Unknown | 64bit IO Format:%lld & %llu |
Description
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:
Here the firing region is the sector 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(1N5000, KN) , 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