UVALive - 4253 Archery 暴力

来源:互联网 发布:linux命令行下载mysql 编辑:程序博客网 时间:2024/05/21 07:09

题目大意:有一个人在x轴上射箭,他能移动的范围是[0,L],现在有m个靶子,给出每个靶子的坐标(y坐标和两个x坐标),问这个人能否一箭射到所有的靶子

解题思路:二分枚举这个人所在的位置,计算一下当前位置和所有靶子的角度,维护一个角度区间,表示这个区间内的所有靶子都能射中。如果当前位置和一个靶子的角度(两个角度之间的最小值)大于当前区间的最大值,那么这个人就要向右移动,反之,如果小于当前区间的最小值,那么这个人就要向左移动

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define maxn 5010#define esp 1e-6struct Target{    double y, x_l, x_r;}t[maxn];bool cmp(Target &a, Target &b) {    return a.y < b.y;}double w;int n;int judge(double pos) {    double L = atan2(t[0].y, t[0].x_r - pos);    double R = atan2(t[0].y, t[0].x_l - pos);    for(int i = 1; i < n; i++) {        double l = atan2(t[i].y, t[i].x_r - pos);        double r = atan2(t[i].y, t[i].x_l - pos);        if(r - L < -esp)             return -1;        if(l - R > esp)            return 1;        L = max(L, l);        R = min(R, r);    }    return 0;}bool solve() {    sort(t,t + n, cmp);    double l = 0, r = w;    int mark;    while(r - l > esp) {        double mid = (r + l) / 2;        mark = judge(mid);        if(mark == 0)            return true;        else if(mark == -1)            r = mid;        else            l = mid;    }    return false;}int main() {    int test;    scanf("%d", &test);    while(test--) {        scanf("%lf%d", &w, &n);        for(int i = 0; i < n; i++)            scanf("%lf%lf%lf", &t[i].y, &t[i].x_l, &t[i].x_r);        printf("%s\n", solve()?"YES":"NO");    }    return 0;}
0 0
原创粉丝点击