Codeforces Round #346 (Div. 2) D. Bicycle Race(点在多边形内部)

题意:

判断多少个转点会有危险?

思路:

这个题有一万种做法,因为数据较小!
1. O(1) 公式 (n4)/2
2. O(n) 扫一遍点,判断叉积是否大于零?
3. O(n2) 利用计算几何的知识,判断某个点是否在多边形内部,下面说一下这种解法:

判断一个点是否在多边形内部,具体有三种方法:
- 面积法
- 内角和
- 射线交点

这里呢,个人觉得用判断射线交点比较简单,如果射线与多边形的交点个数为奇数,那么该点在多边形内部,否则,就在外部!

如果射线与某条线段重合呢?如果射线与线段恰好相交在顶点呢?会不会重复计数呢?

if else …..if else ……(循环中)

这里,我推荐随机化,就是随机一个点,实在不行随机两个点,是不是很稳?
所以借这个题,学习一波判断点是否在多边形内部,还有学习随机化在计算几何的巧妙应用!

代码:
#include <bits/stdc++.h>
#define eps 1e-8
using namespace std;
const int N = 1e3 + 10;
int n;
typedef double TP;
struct Point
{
    TP x, y;
    Point(TP x = 0, TP y = 0) :x(x), y(y){}
    void input()
    {
        scanf("%lf %lf", &x, &y);
    }
    Point operator - (const Point& p)
    {
        return Point(x - p.x, y - p.y);
    }
    TP operator ^ (const Point& p)
    {
        return (x * p.y - y * p.x);
    }
};
Point p[N];
struct Line
{
    Point S, E;
    Line(Point _s = Point(), Point _e = Point()): S(_s), E(_e) {}
    void input()
    {
        S.input(), E.input();
    }
};
int dcmp(double x)
{  
    if(fabs(x) < eps) return 0;  
    else return x < 0 ? -1 : 1;  
}
double dis(Point& a, Point& b)
{
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
TP cross(Point& S, Point& E, Point& O)
{
    return (S - O) ^ (E - O);
}
bool onLine(Line a, Line b)
{
    return dcmp(cross(a.S, a.E, b.S)) == 0 && dcmp(cross(a.S, a.E, b.E)) == 0;
}
bool isSegCross(Line a, Line b)
{
    int ok1 =  dcmp(cross(a.S, a.E, b.S)) * dcmp(cross(a.S, a.E, b.E));
    int ok2 =  dcmp(cross(b.S, b.E, a.S)) * dcmp(cross(b.S, b.E, a.E));
    return ok1 < 0 && ok2 < 0;
}
int getd(Point s, Point e)
{
    if(s.x == e.x) {
        if(s.y < e.y) return 2;
        return -2;
    }
    else {
        if(s.x < e.x) return 1;
        return -1;
    }
}
Point getp(int d,Point s)
{
    if(d == 1) return Point(1e5 + 3, rand());
    else if(d == -1) return Point(-1e5 - 3, rand());
    else if(d == 2) return Point(rand(), 1e5 + 3);
    return Point(rand(), -1e5 - 3);
}
Point getpL(int d,Point s)
{
    if(d == 1) return Point(s.x + 0.5, s.y);
    else if(d == -1) return Point(s.x - 0.5, s.y);
    else if(d == 2) return Point(s.x, s.y + 0.5);
    return Point(s.x, s.y - 0.5);
}
bool check(Line t)
{
    int cnt = 0;
    for(int i = 0;i < n;i ++) if(isSegCross(Line(p[i], p[i+1]), t)) cnt ++;
    return cnt % 2 == 1;
}
int main()
{
    // freopen("in.txt","r",stdin);
    scanf("%d", &n);
    for(int i = 0;i <= n;i ++) {
        p[i].input();
    }
    int ans = 0, d = 2;
    for(int i = 1;i < n;i ++) {
        Point s = getpL(d, p[i]);
        if(check(Line(s, getp(d, p[i]))) || check(Line(s, getp(d, p[i])))) ans ++;
        d = getd(p[i], p[i+1]);
    }
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值