题目连接:uva 1421 & uvalive 4253 Archery
题目大意:有n个平行与x轴的线段,每条线段代表一个靶子。你的任务是判断是否可以站在x轴上[0,w]区间的某个位置射箭,使得箭能穿过所有靶子。
解题思路:二分人站的位置,对于每个位置,维护靶子的可以击中的角度,如果出现靶子的区间,l > R,人左移;r < L人右移。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
const int N = 5005;
const double esp = 1e-6;
int n, t;
double w;
struct Seg {
double d, l, r;
}s[N];
bool cmp(Seg a, Seg b) {
return a.d < b.d;
}
int judge(double x) {
double L = atan2(s[0].d, s[0].r - x);
double R = atan2(s[0].d, s[0].l - x);
for (int i = 1; i < n; i++) {
double l = atan2(s[i].d, s[i].r - x);
double r = atan2(s[i].d, s[i].l - x);
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(s, s + n, cmp);
double l = 0, r = w;
while (r - l > esp) {
double mid = (l+r)/2;
int k = judge(mid);
if (k == 0) return true;
else if (k == -1) r = mid;
else l = mid;
}
return false;
}
int main () {
scanf("%d", &t);
while (t--) {
scanf("%lf%d", &w, &n);
for (int i = 0; i < n; i++)
scanf("%lf%lf%lf", &s[i].d, &s[i].l, &s[i].r);
printf("%s\n", solve() ? "YES" : "NO");
}
return 0;
}