2015’12杭电校赛1002 Polygon (计算几何)

题解:

直接找一个求直线截多边形长度模板就可以A了,模板题

代码


/****************************************************************** 题意: 多边形有n个顶点,输入m条直线,分别输出它们在多边形内的长度,边界也算 算法: 求出直线与多边形的所有交点, 排序后,判断每一段线段是否在多边形内(判断中点是否在多边形内),求和。 *******************************************************************/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

struct Point
{
    double x;
    double y;
} p[1001], px[10001];
int n;
double eps=1e-8;

int cmp(Point a, Point b)
{
    if(abs(a.x-b.x)<eps)
        return a.y<b.y;
    return a.x<b.x;
}

double dist(Point a,Point b)//求距离
{
    return sqrt((a.x - b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double direction(Point pi,Point pj,Point pk)
{
    return (pk.x-pi.x)*(pj.y-pi.y)-(pj.x-pi.x)*(pk.y-pi.y);
}

bool on_segment(Point pi,Point pj,Point pk)//判断点pk时候在线段pi, pj上
{
    if(direction(pi, pj, pk)==0)
    {
        if(pk.x>=min(pi.x,pj.x)&&pk.x<=max(pi.x,pj.x)&&pk.y>=min(pi.y,pj.y)&&pk.y<=max(pi.y,pj.y))
            return true;
    }
    return false;
}

bool segments_intersect(Point p1,Point p2,Point p3,Point p4)//判断线段是否相交
{
    double d1=direction(p3,p4,p1);
    double d2=direction(p3,p4,p2);
    double d3=direction(p1,p2,p3);
    double d4=direction(p1,p2,p4);
    if(d1*d2<0&&d3*d4<0)
        return true;
    else if(d1==0&&on_segment(p3,p4,p1))
        return true;
    else if(d2==0&&on_segment(p3,p4,p2))
        return true;
    else if(d3==0&&on_segment(p1,p2,p3))
        return true;
    else if(d4==0&&on_segment(p1,p2,p4))
        return true;
    return false;
}

Point intersection(Point a1, Point a2, Point b1, Point b2)//计算线段交点
{
    Point ret = a1;
    double t = ((a1.x - b1.x) * (b1.y - b2.y) - (a1.y - b1.y) * (b1.x - b2.x))
               / ((a1.x - a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x - b2.x));
    ret.x += (a2.x - a1.x) * t;
    ret.y += (a2.y - a1.y) * t;
    return ret;
}

int InPolygon(Point a)//判断点是否在多边形的内部
{
    int i;
    Point b,c,d;
    b.y=a.y;
    b.x=1e15;//定义射线
    int flag=0;
    int count=0;
    for(i=0; i<n; i++)
    {
        c = p[i];
        d = p[i + 1];
        if(on_segment(c,d,a))//该点在多边形的一条边上
            return 1;
        if(abs(c.y-d.y)<eps)
            continue;
        if(on_segment(a,b,c))//和顶点相交的情况,如果y值较大则取
        {
            if(c.y>d.y)
                count++;
        }
        else if(on_segment(a,b,d))//和顶点相交的情况,如果y值较大则取
        {
            if(d.y>c.y)
                count++;
        }
        else if(segments_intersect(a,b,c,d))//和边相交
            count++;
    }
    return count%2;//当L和多边形的交点数目C是奇数的时候,P在多边形内,是偶数的话P在多边形外。
}

bool Intersect(Point s,Point e,Point a,Point b)
{
    return direction(e,a,s)*direction(e,b,s)<=0;
}//所在直线相交

double calculate(Point s,Point e)
{
    int i,j,k=0;
    double sum;
    Point a,b,temp;
    for(i=0; i<n; i++) //遍历所有点计算交点
    {
        a=p[i];
        b=p[i+1];
        if(abs(direction(e,a,s))<eps&&abs(direction(e,b,s))<eps)
        {
            px[k++]=a;
            px[k++]=b;
        }
        else if(Intersect(s,e,a,b))//两直线相交
        {
            px[k++]=intersection(s,e,a,b);//两直线交点
        }
    }
    if(k==0)
        return 0.0;
    sort(px,px+k,cmp); // 排序,由于割线是直线,所以交点必定线性分布
    px[k]=px[0];
    sum=0;
    for(i=0; i<k-1; i++)
    {
        a=px[i];
        b=px[i+1];
        temp.x=(a.x+b.x)/2.0;
        temp.y=(a.y+b.y)/2.0;
        if(InPolygon(temp))//如果两点的中点在多边形外部,说明直线在外部
            sum+=dist(a,b);
    }
    return sum;
}

int main()
{
    int q,i,j;
    double sum;
    Point s,e;
    //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        if(n==0)
            break;
        for(i=0; i<n; i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        p[n]=p[0];
            scanf("%lf%lf%lf%lf",&s.x,&s.y,&e.x,&e.y);
            sum=calculate(s,e);
            printf("%.3f\n",sum);
    }
    return 0;
}

题目

Polygon

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 238 Accepted Submission(s): 52

Problem Description

Give you a simple polygon and a line, and your task is to calculate the length of the line which is covered by the polygon.

Input

There are several test cases.
Each test case starts with one non-negative integer n (3 <= n <= 1000) giving the number of the vertices of the polygon. Then following n lines, each line contains two real numbers standing for the x and y coordinates of a vertex. The vertices are given either in clockwise or counterclockwise order. Then four real numbers (sx, sy, tx, ty), standing for the coordinates of the two points of the line.
All real numbers are between -100000 and 100000.

Output

For each case print the total length of the line that covered by the polygon, with 3 digits after the decimal point.

Sample Input

4
0 0
0 1
1 1
1 0
0 0 1 1
4
0 0
0 1
1 1
1 0
0 0 1 0
9
0 0
0 2
1 1
2 2
3 1
4 2
5 1
6 2
6 0
0 1 6 1

Sample Output

1.414
1.000
6.000

你可能感兴趣的:(2015’12杭电校赛1002 Polygon (计算几何))