题意:
给定一个N≤103个点的简单多边形,不一定是凸的,存在多点共线
给定M≤100条直线,求直线与简单多边形的公共部分长度
分析:
时限0.5s,求出所有交点,并判断每条线段是否在多边形内,O(m∗n2)肯定要T,考虑优化判断线段在多边形内
接下来考虑包含全部情况的锯齿形的做法
![]()
AB为直线,C∼N为多边形
先看2条规范相交的CD、DE与AB的交点Q、K,我们发现QK的长度需要计算,但是KL不算
那么我们标记一下,Q为+2,K为−2,只在标记值不为0的时候加到答案上,那么QK为2,KL为0,显然只算了QK
我们发现如果将不规范相交的G标记为−2的话,那么GR就无法被计算了
由于不规范相交不会影响线段包含的结果,我们只需要将标记做小一点就达到要求了,−1即可,当然+−还是按照线段的方向决定
至于多点共线的情况,我们发现中间共线的点都是无用的,只有2个最外端点有用,直接不管中间的共线点即可
当然由于交点肯定在直线上,我们不用求出交点,求出交点的方向向量的系数即可,最终答案乘上方向向量的长度,可以降低误差
代码:
//
// Created by TaoSama on 2016-01-19
// Copyright (c) 2015 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
#define double long double
const double EPS = 1e-8;
int sgn(double x) {
return x < -EPS ? -1 : x > EPS;
}
struct Point {
double x, y;
Point() {}
Point(double x, double y): x(x), y(y) {}
void read() {cin >> x >> y;}
Point operator-(const Point& p) {
return Point(x - p.x, y - p.y);
}
double operator*(const Point& p) {
return x * p.x + y * p.y;
}
double operator^(const Point& p) {
return x * p.y - y * p.x;
}
double length() {return hypotl(x, y);}
} poly[N];
using Vec = Point;
double getIntersection(Point p, Vec v, Point q, Vec w) {
return (w ^ (p - q)) / (v ^ w);
}
int n, q;
double gao(Point p, Vec v) {
double ret = 0;
vector<pair<double, int> > pos;
for(int i = 1; i <= n; ++i) {
int s1 = sgn(v ^ (poly[i] - p));
int s2 = sgn(v ^ (poly[i + 1] - p));
if(s1 == s2) continue; //collinear or no intersection
double o = getIntersection(p, v, poly[i], poly[i + 1] - poly[i]);
if(s1 > s2) pos.push_back({o, s1 && s2 ? 2 : 1});
else pos.push_back({o, s1 && s2 ? -2 : -1});
}
sort(pos.begin(), pos.end());
int flag = 0;
for(int i = 0; i + 1 < pos.size(); ++i) {
flag += pos[i].second;
if(flag) ret += pos[i + 1].first - pos[i].first;
}
return ret * v.length();
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
cin >> n >> q;
for(int i = 1; i <= n; ++i) poly[i].read();
poly[n + 1] = poly[1];
while(q--) {
Point A, B;
A.read(); B.read();
cout << fixed << setprecision(20) << gao(A, B - A) << '\n';
}
return 0;
}