题目大意就是给出一个凸多边形,再给出一些线段,求出每条线段在多边形内部的长度。
首先把给出的点按极角排序,求出这个凸多边形。
关键是怎样判断一条线段是否与多边形相交,交点,以及内部的长度。
判断一条线段是否与多边形相交,即判断其与多边形每条边是否有交点。
引理:若线段AB与线段CD相交,那么A、B分别在CD两侧,C、D分别在AB两侧,反之成立。
判断两个点分别在线段两侧,我们可以用叉积,即若(CA×CD)*(CB×CD)<=0时,A、B在CD两侧(或AB与CD共线)。
当(CA×CD)*(CB×CD)==0 && (AC×AB)*(AD×AB)==0时,AB与CD共线,这种情况要排除,不算交点。
若线段相交,用点法式表示两条直线为(P,v)、(Q,w),前一项为直线上一点,后一项为方向向量,即直线上任意一点都可以表示为P+t*v。
设u=P-Q,k=cross(w,u)/cross(v,w),则交点为P+k*v(白书上的...)。
把这些交点存入数组中,由于多边形顶点会被计算两次,所以要去重。
求出交点的同时,我们还要判断要求的线段两端点是否在多边形内部,同样用叉积就好了,对每条线段依次判断。
求出以上内容后,输出也要注意点细节:
(端点在线段上不算在多边形内)
当两端点都在多边形内部时,直接计算线段长度;
当有一端点在多边形内部时,计算在内部的那个点和交点的距离;
当线段与多边形有两交点时,计算两交点的距离;
输出0。
over,其实这道题坑的就是细节稍多额,wa了很多次......
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 405;
const double MAXL = 30005;
int N, M;
struct Point
{
double x, y;
}v[MAXN], ta, tb;
int minf;
Point operator - (const Point &A, const Point &B)
{
Point tmp = {A.x-B.x, A.y-B.y};
return tmp;
}
Point operator + (const Point &A, const Point &B)
{
Point tmp = {A.x+B.x, A.y+B.y};
return tmp;
}
Point operator * (const double &A, const Point &B)
{
Point tmp = {A*B.x, A*B.y};
return tmp;
}
bool operator == (const Point &A, const Point &B)
{
return (A.x == B.x && A.y == B.y);
}
double time(Point A, Point B)
{
return A.x*B.y-A.y*B.x;
}
int find()
{
int re = 1;
for(int i = 0; i < N; ++i)
if(v[re].x > v[i].x || (v[re].x == v[i].x && v[re].y > v[i].y)) re = i;
return re;
}
bool cmp(const Point &A, const Point &B)
{
return (time(v[0]-A, v[0]-B) > 0);
}
bool vcmp (const Point &A, const Point &B)
{
return (A.x < B.x || (A.x == B.x && A.y < B.y));
}
Point get(Point P, Point v, Point Q, Point w)
{
Point u = P-Q;
double t = time(w, u)/time(v, w);
return P+t*v;
}
Point p = {0, 0};
bool online = false;
bool intersect(Point A, Point B, Point C, Point D)
{
double c1 = time(B-A, C-A), c2 = time(B-A, D-A), c3 = time(D-C, A-C), c4 = time(D-C, B-C);
if(c1 == 0 && c2 == 0) { online = true;return false; }
if(c1*c2 <= 0 && c3*c4 <= 0)
{
p = get(A, B-A, C, D-C);
return true;
}
else return false;
}
double dis(const Point &A, const Point &B)
{
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
double solve()
{
Point inter[4] = {-MAXL, -MAXL, -MAXL, -MAXL}, real[2] = {-MAXL, -MAXL};
int top = 0, topr = 0;
bool a = true, b = true;
online = false;
for(int i = 0, j = N-1; i < N; j = i++)
{
if(a && time(v[j]-ta, v[i]-ta) <= 0) a = false;
if(b && time(v[j]-tb, v[i]-tb) <= 0) b = false;
if(intersect(v[j], v[i], ta, tb))
inter[top++] = p;
if(online) { a = b = top = 0;break; }
}
sort(inter, inter+top, vcmp);
for(int i = 0; i < top; ++i)
if(i && inter[i] == inter[i-1]) continue;
else real[topr++] = inter[i];
if(a && b) return dis(ta, tb);
else if(a) return dis(ta, real[0]);
else if(b) return dis(tb, real[0]);
else if(topr == 2) return dis(real[0], real[1]);
else return 0;
}
int main()
{
scanf("%d", &N);
for(int i = 0; i < N; ++i)
scanf("%lf%lf", &v[i].x, &v[i].y);
minf = find();
swap(v[0], v[minf]);
sort(v+1, v+N, cmp);
scanf("%d", &M);
for(int i = 0; i < M; ++i)
{ scanf("%lf%lf%lf%lf", &ta.x, &ta.y, &tb.x, &tb.y);
printf("%.2lf\n", solve());
}
return 0;
}