题目链接:uva 1432 - Fire-Control System
题目大意:有一个武器位于(0,0)的位置,它的攻击范围为一个扇形,现在要求攻击到k个点,并且面积越小。
解题思路:首先先按照半径排序,这样可以计算出比该点半径小的点有几个。然后按照角度排序,枚举半径,如果小于当前半径的点的个数不足k可以跳过该半径。需要注意的是第2、3象限的点。
#include <stdio.h> #include <string.h> #include <math.h> #include <set> #include <queue> #include <algorithm> using namespace std; const int N = 5005; const int INF = 0x3f3f3f3f; const double pi = acos(-1.0); struct point { int x, y, cnt; double r, c; void get() { scanf("%d%d", &x, &y); r = sqrt(x * x * 1.0 + y * y * 1.0); c = atan2(y, x); cnt = 1; } }p[N], rec[N]; int n, k; bool cmpR(const point& a, const point& b) { return a.r < b.r; } bool cmpC(const point& a, const point& b) { return a.c < b.c; } void init () { for (int i = 0; i < n; i++) p[i].get(); sort(p, p + n, cmpR); for (int i = 1; i < n; i++) p[i].cnt += p[i-1].cnt; } double solve () { if (k == 0) return 0; double ans = INF; set<double> v; sort(p, p + n, cmpC); for (int i = 0; i < n; i++) { if (p[i].cnt < k) continue; double R = p[i].r, C = 2 * pi; if (v.find(R) != v.end()) continue; v.insert(R); int tmp = 0; for (int j = 0; j < n; j++) if (p[j].r < R || fabs(p[j].r - R) < 1e-9) { rec[tmp++] = p[j]; if (tmp >= k) C = min(C, rec[tmp-1].c - rec[tmp-k].c); } if (tmp < k) continue; for (int j = 0; j < k - 1; j++) C = min(C, rec[j].c - rec[tmp+j-k+1].c + 2 * pi); ans = min(ans, R * R * C / 2); } return ans; } int main () { int cas = 1; while (scanf("%d%d", &n, &k) == 2 && n + k) { init(); printf("Case #%d: %.2lf\n", cas++, solve()); } return 0; }