HDU3867 计算几何扫描线

转载自 AcCry
题意:原子弹爆炸,一些互不相交的线段,求能辐射到的线段(可以将原子弹爆炸点视为泛光源)
以辐射源为中心对周围的点按照极坐标角度进行排序,然后在极坐标上使用扫描线方法。
维护一个集合,集合内的元素是与扫描线相交的线段,排序依据是线段与扫描线的交点到辐射源的距离。该集合中的最小元素就是被照射到的线段。

有关容器(set)排序依据的说明:

在扫描线运动前后,如果有两个线段存在于容器中,这两个线段与扫描线的交点到辐射源的距离远近关系不会发生变化。若发生变化,表示扫描线运动范围内两个线段有交点,与题目提供的已知条件不符。




PS:此题各种重载 各种stl

  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <cmath>  
  4. #include <set>  
  5. #include <algorithm>  
  6. using namespace std;  
  7. #define EPS 1e-8  
  8. #define LS0(a) (a << 1)  
  9. #define LS1(a) ((a << 1) | 1)  
  10.   
  11. const int MAXN = 20010;  
  12. struct Point {   
  13.     double x, y;  
  14.     Point(double _x = 0.0, double _y = 0.0): x(_x), y(_y) {}  
  15.     Point operator + (const Point &b) const {  
  16.         return Point(x + b.x, y + b.y);  
  17.     }  
  18.     Point operator - (const Point &b) const {  
  19.         return Point(x - b.x, y - b.y);  
  20.     }  
  21.     double operator ^ (const Point &b) const {  
  22.         return x * b.y - y * b.x;  
  23.     }  
  24.     bool operator < (const Point &b) const {  //逆时针  
  25.         return x * b.y < y * b.x;  
  26.     }  
  27.     void input() {  
  28.         scanf("%lf%lf", &x, &y);  
  29.     }  
  30.     double diso() {  
  31.         return sqrt(x * x + y * y);  
  32.     }  
  33.   
  34. }cur,ps[MAXN];  
  35.   
  36. Point lnlncross_pt(Point aa, Point ad, Point ba, Point bd) { // 求直线交点  
  37.     ad = ad - aa;  
  38.     bd = bd - ba;  
  39.     double tmp = bd ^ ad;  
  40.     return Point(  
  41.         (ad.x * bd.x * (ba.y - aa.y) + aa.x * bd.x * ad.y - ba.x * ad.x * bd.y) / tmp,  
  42.         (ad.y * bd.y * (aa.x - ba.x) + ba.y * ad.y * bd.x - aa.y * bd.y * ad.x) / tmp);  
  43. }  
  44.   
  45. struct Item { // 扫描线的点类型  
  46.     Point *u, *v;  
  47.     int type; // 1: 线段起点; 0: 线段终点;  
  48.     int sgid; // 线段序号  
  49.     Item(Point *_u = NULL, Point *_v = NULL, int _ty = 0, int _id = 0)  
  50.         : u(_u), v(_v), type(_ty), sgid(_id) {}  
  51.     bool operator < (const Item &b) const {  
  52.         if(u == b.u && v == b.v)  
  53.             return false;  
  54.         Point au = lnlncross_pt(Point(0.0, 0.0), cur, *u, *v);  
  55.         Point bu = lnlncross_pt(Point(0.0, 0.0), cur, *b.u, *b.v);  
  56.         return au.diso() < bu.diso();  
  57.     }  
  58.   
  59. }item[MAXN];  
  60.   
  61. bool flag[MAXN];  
  62. set<Item> Scan;  
  63.   
  64.                       
  65. bool cmp(const Item &a, const Item &b) { //极角排序 从-PI到-PI内   
  66.         return atan2(a.u->y, a.u->x) < atan2(b.u->y, b.u->x);  
  67.   
  68. }  
  69.   
  70. void inputps(int n) {  
  71.     Point src, a, b;  
  72.     src.input();  
  73.     for(int i = 0; i < n; ++i) {  
  74.         // 读取线段并求得相对于光源的坐标  
  75.         a.input(); a = a - src;  
  76.         b.input(); b = b - src;  
  77.         // 保证线段的极角序  
  78.         if(b < a) swap(a, b);  
  79.         ps[LS0(i)] = a;  
  80.         ps[LS1(i)] = b;  
  81.         item[LS0(i)] = Item(&ps[LS0(i)], &ps[LS1(i)], 0, i);  
  82.         item[LS1(i)] = Item(&ps[LS1(i)], &ps[LS0(i)], 1, i);  
  83.     }  
  84.     sort(item, item + 2 * n, cmp);  
  85. }  
  86.   
  87.   
  88.   
  89. bool sgcross_with_ax(Item &a) {   //与射线相交判断   good 以前不知道的东西  
  90.     Point tmp(-1.0, 0.0);  
  91.     return (*a.u ^ *a.v) * (*a.u ^ tmp) > 0.0  
  92.         && (*a.u ^ tmp) * (tmp ^ *a.v) > 0.0;  
  93. }  
  94.   
  95.   
  96.   
  97. int main() {  
  98.     int n;  
  99.     while(scanf("%d", &n) != EOF) {  
  100.         inputps(n);  
  101.         memset(flag,0,sizeof(flag));  
  102.         // 初始化极角扫描器  初始射线向量为(-1.0,0)  
  103.         Scan.clear();  
  104.         for(int i = 0; i < 2 * n; ++i) {  
  105.                 cur = *item[i].u;  
  106.             if(item[i].type == 1 && sgcross_with_ax(item[i]))  
  107.                 Scan.insert(item[i]);  
  108.         }  
  109.         // 极角扫描  
  110.         for(int i = 0; i < 2 * n; ++i) {  
  111.                 cur = *item[i].u;  
  112.             if(item[i].type == 1)  
  113.                 Scan.insert(item[i]);  
  114.             else  
  115.                 Scan.erase(Item(item[i].v, item[i].u, 1, item[i].sgid));  
  116.             if(!Scan.empty())  
  117.                 flag[Scan.begin()->sgid] = true;  
  118.         }  
  119.         int ans = 0;  
  120.         for(int i = 0; i < n; ++i)  
  121.             if(flag[i])ans ++;  
  122.         printf("%d\n", ans);  
  123.     }  
  124.     return 0;  
  125.   
  126. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算几何算法(含源代码) ㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断圆是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸凹性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 圆的基本运算 1 .点是否在圆内 20 2 .求不共线的三点所确定的圆 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两圆关系: 24 2.判断圆是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两圆交点: 27 8.两圆公共面积: 28 9. 圆和直线关系: 29 10. 内切圆: 30 11. 求切点: 31 12. 线段的左右旋: 31 13.公式: 32

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值