LA 4253 箭术(二分枚举)

https://vjudge.net/problem/UVALive-4253

题意:

有n个平行于x轴的线段,每条线段代表一个靶子。判断是否可以站在x轴上[0,W]区间内的某个位置射箭。

思路:
二分枚举坐标点,这道题需要用到atan2函数,它返回一个角度值,对于每个靶子,利用atan2函数确定能射中靶子的区间,如果靶子之间区间没有重合部分,说明该坐标点不能射中所有靶子。在下面的代码中,如果返回1,说明需要向右移,如果返回-1,说明需要向左移。

这道题目还需要注意一点的就是精度问题。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 
 7 const int maxn = 5000 + 5;
 8 
 9 double W;
10 int n;
11 
12 struct node
13 {
14     double D, L, R;
15 }a[maxn];
16 
17 bool cmp(node a, node b)
18 {
19     return a.D < b.D;
20 }
21 
22 int judge(double pos)
23 {
24     double R = atan2(a[0].D, a[0].R - pos);
25     double L = atan2(a[0].D, a[0].L - pos);
26     for (int i = 1; i < n; i++)
27     {
28         double r = atan2(a[i].D, a[i].R - pos);
29         double l = atan2(a[i].D, a[i].L - pos);
30 
31         if (l - R < -0.000001)    return -1;
32         if (r - L > 0.000001)    return 1;
33 
34         L = min(L, l);
35         R = max(R, r);
36     }
37     return 0;
38 }
39 
40 
41 int main()
42 {
43     //freopen("D:\txt.txt", "r", stdin);
44     int T;
45     cin >> T;
46     while (T--)
47     {
48         cin >> W >> n;
49         for (int i = 0; i < n; i++)
50             cin >> a[i].D >> a[i].L >> a[i].R;
51         sort(a, a + n, cmp);
52         double l = 0, r = W;
53         int ok = 0;
54         while (r - l>0.0000001)
55         {
56             double mid = (r + l) / 2;
57             int ans = judge(mid);
58             if (ans == 0)
59             {
60                 cout << "YES" << endl;
61                 ok = 1;
62                 break;
63             }
64             else if (ans == 1)  l = mid;
65             else  r = mid;
66         }
67         if(!ok) cout << "NO" << endl;
68     }
69 }
原文地址:https://www.cnblogs.com/zyb993963526/p/6551479.html