ACM: uva 1432 -&n…

Fire-Control System

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:

ACM: <wbr>uva <wbr>1432 <wbr>- <wbr>Fire-Control <wbr>System

 

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 (1 N 5000, K N, followed by Nlines 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个攻击目标的坐标(x,y), 现在要求你至少攻击k个目标,

      并且覆盖至少k个目标的扇形面积最小.

 

解题思路:

      1. 至少覆盖k个目标, 其实我们只需要求出覆盖k个目标即可, 因为覆盖更多的目标只会让解变得

      不优.

      2. 我们可以采用顺时针的方向依次扫描坐标上的点, 覆盖k个点就计算一个扇形面积, 但是问题是

      怎么确定扇形的母线长度? 但是母线的长度的上下界是可以确定的, 就是n个目标到(0,0)距离最大

      和最小. 这样我们就可以从小到大扫描母线的长度, 并且逆时针方向一次扫描目标集是否满足母线

      长度的攻击范围, 用队列存储即可.

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define MAX 5005
const double INF = 1e30;
const double pi = acos(-1.0);

struct Node
{
 int dist;
 double rad;
 bool operator <(const Node &x) const
 {
  return rad < x.rad;
 }
}node[MAX*2];

int n, k;
int qu[MAX*2], dist[MAX];
int front, rear, num;
double ans;

int main()
{
// freopen("input.txt", "r", stdin);
 int caseNum = 1, i, j;
 while(scanf("%d %d", &n, &k) != EOF)
 {
  if(n == 0 && k == 0) break;

  int x, y;
  for(i = 1; i <= n; ++i)
  {
   scanf("%d %d", &x, &y);
   if(x >= 0)
   {
    if(y >= 0) node[i].rad = atan( (y*1.0)/x );
    else node[i].rad = 2*pi - atan( (-y*1.0)/x );
   }
   else
   {
    if(y >= 0) node[i].rad = pi - atan( (y*1.0)/(-x) );
    else node[i].rad = pi + atan( (-y*1.0)/(-x) );
   }

   node[i].dist = x*x+y*y;
   dist[i] = node[i].dist;
  }

  if(n == 0 || k == 0)
  {
   printf("Case #%d: 0.00\n", caseNum++);
   continue;
  }

  sort(dist+1, dist+1*n);
  sort(node+1, node+1+n);

  num = 0;
  dist[0] = -1;
  for(i = 1; i <= n; ++i)
   if(dist[i] != dist[num])
    dist[++num] = dist[i];

  memcpy(node+1+n, node+1, sizeof(node[1])*n);
  for(i = n+1; i <= 2*n; ++i)
   node[i].rad += 2*pi;
  ans = INF;
  for(i = 1; i <= num; ++i)
  {
   int tempDist = dist[i];
   double tempAns = INF;
   front = 1, rear = 0;
   for(j = 1; j <= n; ++j)
   {
    if(node[j].dist <= tempDist)
    {
     qu[++rear] = j;
     if(rear == k) break;
    }
   }

   if(rear == k)
   {
    tempAns = node[ qu[rear] ].rad - node[ qu[front] ].rad;
    for(j = qu[rear]+1; j <= 2*n && qu[front] <= n; ++j)
    {
     if(node[j].dist <= tempDist)
     {
      qu[++rear] = j;
      front++;
      double temp = node[ qu[rear] ].rad - node[ qu[front] ].rad;
      if(temp < tempAns) tempAns = temp;
     }
    }

    tempAns *= tempDist;
    if(ans > tempAns) ans = tempAns;
   }
  }

  printf("Case #%d: %.2lf\n", caseNum++, ans/2);
 }

 return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值