HDU - 4197几何+贪心

 HDU - 4197几何+贪心

Description

John loves programming contests. There is just one problem: his team is not very good at programming. This usually doesn't bother him, but what does bother him is that everyone gets a balloon for every correct submission. John's team never gets any balloons, while other teams get one balloon after the other. This frustrates him, so John would like to see that all other teams have no balloons either. 
This year he has a plan to achieve just that. John has hired a ninja to pop all balloons for him. At any time during the contest, he can call for the ninja to come down through a hole in the ceiling and pop all balloons by using his shurikens (ninja stars), before leaving through the hole in the ceiling again. Of course the ninja wants to use as few of his precious shurikens as possible. Therefore, John must write a program that computes how many shurikens are needed to pop all balloons. Because all balloons are usually at approximately the same height, he can model the problem as a 2-dimensional problem. He sets the location of the ninja (where he comes in) as the origin (0, 0) and uses circles to model the balloons. To be on the safe side, these circles can have different radii. Shurikens are assumed to be thrown from the origin and move in a straight line. Any circle/balloon crossed by this haline will be popped by this shuriken. The question then becomes: how many halines rooted at the origin are necessary to cross all circles? 
Of course, as mentioned above, John is not a very good programmer, so he asks you to make this program for him. Can you help him out? You might get a balloon if you get it right... 
 

Input

The first line of the input contains a single number: the number of test cases to follow. Each test case has the following format: 
1.One line with a single integer n (0 <= n <= 1,000): the number of balloons. 
2.n lines, each containing three integers xi,yi (-10^4 <= xi,yi <= 10^4), and ri (1 <= ri <= 10^4),describing the circle used to model the ith balloon, where (xi, yi) is the center of the circle and ri is the radius. 
You can assume that two lines (rooted at the origin) that are tangent to two distinct circles make an angle of at least 10^-6 radians at the origin. Furthermore, the circles do not cross each other (but can touch) and do not contain the origin.
 

Output

For every test case in the input, the output should contain one integer on a single line: the minimum number of shurikens the ninja needs to pop all balloons.
 

Sample Input

     
     
2 5 2 0 1 5 0 2 0 3 2 -4 0 2 0 -2 1 5 4 1 3 5 -5 3 0 -4 2 -4 4 3 -10 3 3
 

Sample Output

     
     
4 3

题意:

平面内有一些圆形气球,用圆心坐标和半径给出,有一个忍者在坐标(0,0)点,忍者可以发射射线来击破气球,求忍者最少需要发射多少射线来击破所有气球,题目保证气球不相交,球原点不包含在任何气球内,并且任意两条与圆相切的射线的夹角大于1e-6。

解题思想:

对每个气球都有一个能击破它的夹角范围,假如我们枚举最开始从那个气球来击破,那么剩下的问题就是冲某个气球开始击破最少需要发射几次射线,这个问题可以用贪心解决,将气球的击破夹角按起始角度排序,若击破某个气球的同时,能够顺带击破其他气球,那就将这些气球一起击破,直到出现一个气球必须从新发射射线为止,这个贪心思想仔细想应该还是能想通的。还要注意的是因为角度是循环的,所以要把角度区间加上2*pi后加到原来的区间数组后面,每次贪心击破n个气球即可。考虑复杂du,枚举O(n),贪心O(n),总O(N^2);

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<queue>
#include<vector>
#include<list>
//#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
#define INF 0x3f3f3f3f
int x[1005],y[1005],r[1005];
int n;
const double pi=atan(1.0)*4;
double get(int x,int y)
{
    if(x==0)
        if(y>0) return pi/2;
        else return 3*pi/2;
    if(y==0)
        if(x<0) return pi;
        else return 0;
    if(x>0&&y>0)
        return atan(1.0*y/x);
    else if(x<0&&y>0) return pi+atan(1.0*y/x);
    else if(x<0&&y<0) return pi+atan(1.0*y/x);
    else return pi*2+atan(1.0*y/x);
}
struct P{double s,len;};
int cmp(P& a,P& b)
{
    if(a.s==b.s) return a.len<b.len;
    return a.s<b.s;
}
vector<P> vec;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        vec.clear();
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d%d",&x[i],&y[i],&r[i]);
        for(int i=1;i<=n;i++)
        {
            double apha=get(x[i],y[i]);
            double dis=sqrt(1.0*x[i]*x[i]+y[i]*y[i]);
            double theta=asin(1.0*r[i]/dis);
            double s=apha-theta;
            if(s<0) s+=2*pi;
            double len=2*theta;
            vec.push_back((P){s,len});
            vec.push_back((P){s+2*pi,len});
        }
        sort(vec.begin(),vec.end(),cmp);
        int Min=INF;
        for(int i=0;i<n;i++)
        {
            double r=-INF;
            int cost=0;
            for(int j=i;j<i+n;j++)
            {
                if(r-vec[j].s>1e-6) r=min(r,vec[j].s+vec[j].len);
                else cost++,r=vec[j].s+vec[j].len;
            }
            Min=min(Min,cost);
        }
        printf("%d\n",n==0?0:Min);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值