题意:
判断多少个转点会有危险?
思路:
这个题有一万种做法,因为数据较小!
1. O(1) 公式 (n−4)/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;
}