HDU 4445 扫描线
来源:互联网 发布:怎么查看手机支持网络 编辑:程序博客网 时间:2024/06/07 03:06
HDU 4445
题目链接:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=33707
题意:
有区间[L1,R1]和[L2,R2]。
现在站在0点,且高度为h的地方。有n个炮筒,炮筒的炮弹速度不一样,且均已一个自己确定的角度发射。问最多有多少个炮筒,可以打到[L1,R1]区间且所有的炮弹不会打到[L2,R2]区间。
思路:
复现的时候银牌题,对于每个角度每个炮有一个打击范围。然而当时公式推错推成只要是45度角,炮就有最远的打击范围。实际上最远射程是与速度有关系的。当这种式子十分复杂的时候,二分三分就可以上了。有暴力枚举角度(m分角度)过的。
正解是扫描线。
扫描线在大白书第一章第三节有介绍,具体好像都会和一些数据结构结合使用。具体理解就是把一个平面的坐标轴看成以x方向长度为1、y方向无限长的细条。当它在某个值的时候就会覆盖多少多少区间的问题。所以对于每个区间有一个事件数,左端点位进入这个事件,右端点位离开这个事件。
再用人听得懂的话说,一个坐标在左端点和右端点中间的时候,这个区间是有效的。所以把每个区间的左右端点都以两个不同值得形式(通常左端点值为1,表示增加一个区间,右端点值为-1)存入数组,然后进行排序一个个往后遍历即可。
处理的时候如果两个端点坐标相同,根据题目具体意思(到底是开区间还是闭区间)来确定左右端点的优先性。
本题是裸的扫描线。存在[L1,R1]和[L2,R2]区间时两端点角度、不合法区间设值为无限大表示当前角度不合法、合法区间设值为1表示当前合法即可。
注意最远射程在区间中(比如[L1,R1])时,这个点不算数,因为优先级不好确定。有都加进去过的如final队http://blog.csdn.net/ALPC_NeverFarewell/article/details/39397673,原因不详……
源码:
#include <cstdio>#include <cstring>#include <cmath>#include <cstring>#include <algorithm>#include <iostream>#include <queue>#include <string>using namespace std;const int MAXN = 200 + 5;const double PI = acos(-1.0);const double eps = 1e-8;const double g = 9.8;int n;double v[MAXN], pos[4], h;double max_ang[MAXN];int cnt;int sgn(double a){ return a > eps ? 1 : (a < -eps ? -1 : 0);}double dis(double v, double ang){ double vx = v * cos(ang); double vy = v * sin(ang); double vt = vy * vy + 2 * g * h; vt = max(vt, 0.0); double t = (vy + sqrt(vt)) / g; return t * vx;}void cal_max_ang(int mark){ double l = - PI / 2.0, r = PI / 2.0; int cnt = 100; while(cnt--){ double temp = (-l + r) / 3.0; if(sgn(dis(v[mark], l + temp) - dis(v[mark], r - temp)) > 0) r = r - temp; else l = temp + l; } max_ang[mark] = l;}struct D{ double u; int cnt; int state; void init(double _u, int _state, int _cnt){u = _u, state = _state, cnt = _cnt;}}d[MAXN * 8];double dis2(double v, double x, double ang){ double t = x / (v * cos(ang)); return g / 2 * t * t - v * sin(ang) * t;}double cal2(double v, double x, double l, double r){ int cnt = 100; while(cnt--){ double temp = (l + r) / 2.0; if(sgn(dis2(v, x, temp) - h) > 0) r = temp; else l = temp; } return l;}double cal1(double v, double x, double l, double r){ int cnt = 100;// printf("x = %f\n", x); while(cnt--){ double temp = (l + r) / 2.0;// printf("temp = %f, dis2(v, x, temp) = %f\n", temp, dis2(v, x, temp)); if(sgn(dis2(v, x, temp) - h) >= 0) l = temp; else r = temp; } return l;}void solve(){ cnt = 0; for(int i = 0 ; i < n ; i++){ cal_max_ang(i);// printf("max_ang[%d] = %f\n", i, max_ang[i]); double td = dis(v[i], max_ang[i]); if(sgn(td - pos[0]) >= 0 && sgn(td - pos[1]) <= 0){ double ang1 = cal1(v[i], pos[0], -PI / 2 + eps, max_ang[i]);// double ang2 = max_ang[i]; d[cnt++].init(ang1, 0, 1);// d[cnt++].init(ang2, 1, -1);// ang2 = max_ang[i]; ang1 = cal2(v[i], pos[0], max_ang[i], PI / 2 - eps);// d[cnt++].init(ang2, 0, 1); d[cnt++].init(ang1, 1, -1); } else if(sgn(td - pos[0]) >= 0){ double ang1 = cal1(v[i], pos[0], -PI / 2 + eps, max_ang[i]); double ang2 = cal1(v[i], pos[1], -PI / 2 + eps, max_ang[i]); d[cnt++].init(ang1, 0, 1); d[cnt++].init(ang2, 1, -1); ang1 = cal2(v[i], pos[0], max_ang[i], PI / 2 - eps); ang2 = cal2(v[i], pos[1], max_ang[i], PI / 2 - eps); d[cnt++].init(ang2, 0, 1); d[cnt++].init(ang1, 1, -1); } if(sgn(td - pos[2]) >= 0 && sgn(td - pos[3]) <= 0){ double ang1 = cal1(v[i], pos[2], -PI / 2 + eps, max_ang[i]); double ang2 = max_ang[i]; d[cnt++].init(ang1, 0, -998);// d[cnt++].init(ang2, 1, 998); ang1 = cal2(v[i], pos[2], max_ang[i], PI / 2 - eps);// d[cnt++].init(ang2, 0, -998); d[cnt++].init(ang1, 1, 998); } else if(sgn(td - pos[2]) > 0){ double ang1 = cal1(v[i], pos[2], -PI / 2 + eps, max_ang[i]); double ang2 = cal1(v[i], pos[3], -PI / 2 + eps, max_ang[i]); d[cnt++].init(ang1, 0, -998); d[cnt++].init(ang2, 1, 998); ang1 = cal2(v[i], pos[3], max_ang[i], PI / 2 - eps); ang2 = cal2(v[i], pos[2], max_ang[i], PI / 2 - eps);// if(fabs(ang1 - 1.140593) < 1e-5 || fabs(ang2 - 1.140593) < 1e-5)// printf("ang1 = %f ,ang2 = %f\n", ang1, ang2); d[cnt++].init(ang1, 0, -998); d[cnt++].init(ang2, 1, 998); }// printf("i = %d, cnt = %d\n", i, cnt); }}bool cmp(D a, D b){ if(sgn(a.u - b.u) != 0) return sgn(a.u - b.u) < 0; else if(a.state != b.state) return a.state < b.state; else{ if(abs(a.cnt) == -998 || abs(b.cnt) == 998) return a.cnt < b.cnt; else return a.cnt > b.cnt; }}int valid1(double ang, double v){ if(dis(v, ang) >= pos[0] && dis(v, ang) <= pos[1]) return 1; return 0;}int valid2(double ang, double v){ if(dis(v, ang) >= pos[2] && dis(v, ang) <= pos[3]) return 1; return 0;}int main(){// freopen("HDU 4445.in", "r", stdin);// freopen("second.out", "w", stdout); while(scanf("%d", &n) != EOF && n){ scanf("%lf%lf%lf%lf%lf", &h, &pos[0], &pos[1], &pos[2], &pos[3]); for(int i = 0 ; i < n ; i++) scanf("%lf", &v[i]); solve(); sort(d, d + cnt, cmp);// for(int i = 0 ; i < cnt ; i++) printf("d[%d], u = %f, state = %d, cnt = %d\n", i, d[i].u, d[i].state, d[i].cnt); int ans = 0; int res = 0; for(int i = 0 ; i < cnt ; i++){// printf("d[i].u = %f, d[i].cnt = %d\n", d[i].u, d[i].cnt);// printf("res = %d\n", res); res += d[i].cnt; ans = max(ans, res); } printf("%d\n", ans); } return 0;}
- HDU 4445 扫描线
- HDU 4007 线扫描
- HDU 3511扫描线
- HDU 1255 扫描线
- HDU 1255 扫描线
- hdu 3642(扫描线)
- hdu 3255(扫描线)
- hdu 4052(扫描线)
- HDU 1828 (扫描线)
- hdu 5738(扫描线)
- hdu 1828 Picture(扫描线)
- Picture hdu 1828 扫描线
- Atlantis - HDU 1542 扫描线
- hdu 1542 Atlantis(扫描线)
- hdu 3255 Farming(扫描线)
- hdu 3265 Posters(扫描线)
- Farming - HDU 3255 扫描线
- hdu 5491 Desiderium(扫描线)
- How to sync a fork repo to keep it up-to-date with the upstream repo on Windows?
- VC++线程同步之关键段
- C++ template 求数组长度
- jQuery中$('#selector).html('')是清空??----html()、text()、val()的区别
- 命令行svn全部操作
- HDU 4445 扫描线
- MySQL日期时间函数大全
- Android签名INSTALL_PARSE_FAILED_NO_CERTIFICATES问题
- webService 的工作原理的介绍
- Feed Reader App
- 【个人重构】数据库设计(1)
- __cpuid, __cpuidex
- LeetCode 20 Valid Parentheses(有效的括号)
- 【算法】插入排序/冒泡排序/选择排序