UVA 1432 - Fire-Control System(技巧枚举+线性扫描)

针对一个武器系统的设计问题,该武器能以0,0为中心进行扇形区域的攻击。任务是找出能有效覆盖指定数量目标点的最小扇形面积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题意:有一个武器在0,0。他的攻击范围是扇形。现在有n个点,要求能攻击到k个点,求最小的扇形面积。

思路:先枚举半径,在按点的极角排序,线性扫描满足半径的点维护ans即可。注意特判k==0的情况,被这个坑惨了还一直找不出来。复杂度为O(n^2)感觉不是很理想的复杂度,还是加点剪枝还是能rank1的

代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <set>
#include <algorithm>
#define INF 0x3f3f3f3f
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;

const int N = 5005;
const double pi = acos(-1.0);

void scanf_(int &num)
{
    char in;
    bool neg=false;
    while(((in=getchar()) > '9' || in<'0') && in!='-') ;
    if(in=='-')
    {
        neg=true;
        while((in=getchar()) >'9' || in<'0');
    }
    num=in-'0';
    while(in=getchar(),in>='0'&&in<='9')
        num*=10,num+=in-'0';
    if(neg)
        num=0-num;
}

int n, k;
struct Point {
	int x, y;
	double r, p;
	int num;
}p[N], save[N];

bool cmpr(Point a, Point b) {
	return a.r < b.r;
}

bool cmpp(Point a, Point b) {
	return a.p < b.p;
}

double cal(Point a, Point b) {
	return a.p - b.p;
}

double solve() {
	if(k == 0) return 0;
	int i, j;
	sort(p, p + n, cmpr);
	for (i = 1; i < n; i++)
		p[i].num += p[i - 1].num;
	double ans = INF;
	sort(p, p + n, cmpp);
	set<double> vis;
	for (i = 0; i < n; i++) {
		if (p[i].num < k) continue;//剪枝1
		int sn = 0; double R = p[i].r, Minp = INF;
		if (vis.find(R) != vis.end()) continue;//剪枝2
		vis.insert(R);
		for (j = 0; j < n; j++) {
			if (p[j].r < R || fabs(p[j].r - R) < 1e-9) {
				save[sn++] = p[j];
				if (sn >= k)
					Minp = min(Minp, cal(save[sn - 1], save[sn - k]));
			}
		}
		if (sn < k) continue;
		for (j = 0; j < k - 1; j++) 
			Minp = min(Minp, cal(save[j], save[(j - k + 1 + sn)]) + 2 * pi);
		ans = min(ans, R * R * Minp / 2);
	}	
	return ans;
}

int main() {
	int cas = 0;
	while (~scanf("%d%d", &n, &k) && n + k) {
		for (int i = 0; i < n; i++) {
			scanf_(p[i].x); scanf_(p[i].y);
			p[i].r = sqrt(p[i].x * p[i].x + p[i].y * p[i].y);
			p[i].p = atan2(p[i].y, p[i].x);
			p[i].num = 1;
		}
		printf("Case #%d: %.2lf\n", ++cas, solve());
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值