现在的位置: 首页 > 综合 > 正文

uva10691 几何水题

2019年03月18日 ⁄ 综合 ⁄ 共 1168字 ⁄ 字号 评论关闭
/*************************************************************
题意:给你一些点,要做一些从原点出发的射线使这些点到最近的射线的距离都不超过 d ,求最少需要做多少根射线
思路:算出每个点到与它距离不大于 d 的射线的角度的区间,然后就是区间选点的问题了,贪心
由于这是一个圈,所以要从每个开始都算一下,一个简单的方法就是把它拓展一倍
**************************************************************/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int pn;
const double PI = acos(-1);
const double eps = 1e-9;
int cmp(double x)
{
    if(x < -eps) return -1;
    if(x > eps) return 1;
    return 0;
}

struct Point
{
    double l, r;
    Point(): l(0.0), r(0.0){}
}p[777];

bool radCmp(const Point &a, const Point &b){return a.r < b.r;}

int solve()
{
    double pre;
    int ans = pn, t;
	sort(p, p + pn, radCmp);
	for (int i = 0; i < pn; i++) {
		p[i + pn].l = p[i].l + 2 * PI;
		p[i + pn].r = p[i].r + 2 * PI;
	}
    for(int i = 0; i < pn; i++)
    {
        int tmp = 1;
        pre = p[i].r;
        for(t = i + 1; t - i < pn; t++)
        {
            if(cmp(p[t].l - pre) > 0)
            {
                tmp++;
                pre = p[t].r;
            }
        }
        ans = min(ans, tmp);
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, d, i, x, y;
        double tmp;
        scanf("%d %d", &n, &d);
        pn = 0;
        for(i = 0; i < n; i++)
        {
            scanf("%d %d", &x, &y);
            int ds2 = x * x + y * y;
            if(ds2 <= d * d) continue;
            p[pn].l = p[pn].r = atan2(1.0 * y, 1.0 * x);
            tmp = asin(1.0 * d / sqrt(1.0 * ds2));
            p[pn].l -= tmp;
            p[pn].r += tmp;
            if(cmp(p[pn].r - PI) > 0)
            {
                p[pn].r -= 2 * PI;
                p[pn].l -= 2 * PI;
            }
            pn++;
        }
        printf("%d\n", solve());
    }
    return 0;
}

抱歉!评论已关闭.