HDU 1154 Cutting a Polygon(基礎計算幾何知識綜合應用)

來源:互聯網
上載者:User

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1154

首先這個題目用到的知識點比較多,而且,思想也很好,精度也有要求,做這個題目對計算幾何的要求還是有一點的

表示這個題目不是像杭電上標難度1的那麼好做;

首先用到很多模板,模板的精度和正確性一定要保證

其次就是這個題目到底是怎麼做

解題思路:求出直線與所有多邊形的交點,然後按照交點排序,按照X從左至右排序,那麼任意兩個相鄰之間的點的連線線段如果在

這個多邊形內部那麼中點一定是在這個多邊形內部,然後基本上注意幾個細節就搞定了

細節一:這個相交要求是直線與線段的非規範相交,也就是端點相交也算,如果這個題目相交於某個端點呢,也不怕,因為只要相交

於某個端點,那麼就一定是兩次,兩次同樣的點排序後一定還是在一起,這個情況就不用考慮了,如果不是非規範相交,那麼萬一一

個交於端點一個交於非端點就完了;

細節二:如果多邊形的某個邊與在這條直線上,那麼這條線段的兩個端點全部加入到點的集合裡面,否則會漏解

代碼(好長的說):

#include <iostream>#include <string.h>#include <algorithm>#include <cmath>#include <stdio.h>using namespace std;#define maxn 1200#define eps 1e-8struct point{    double x;    double y;}po[maxn],rec[maxn];struct line{    point a;    point b;}temp,temp1;double xmulit(point &a,point &b,point &c){    return (a.x-b.x)*(a.y-c.y)-(a.y-b.y)*(a.x-c.x);}bool across(point &a,point &b,point &c,point &d)//直線ab和線段cd是否相交{double p=xmulit(a,b,c),p1=xmulit(a,b,d);if( fabs(p1) <= eps || fabs(p) <= eps ) return true;if( p*p1 < -eps )return true;return false;}bool one_line(point &a,point &b,point &c,point &d)//直線ab和線段cd是否相交{double p=xmulit(a,b,c),p1=xmulit(a,b,d);if( fabs(p1) < eps && fabs(p) < eps ) return true;return false;}bool is_equal(point &a,point &b)//判斷點a和點b是否相等{return (fabs(a.x-b.x) <= eps) && (fabs(a.y-b.y) <=eps);}point intersection(line &u,line &v){point ret=u.a;double t=((u.a.x-v.a.x)*(v.a.y-v.b.y) - (u.a.y-v.a.y)*(v.a.x-v.b.x))/((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));ret.x+=(u.b.x-u.a.x)*t;ret.y+=(u.b.y-u.a.y)*t;return ret;}int n,m;double dis(point &a,point &b){    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}int cmp(point a, point b){    if(fabs(a.x-b.x)<eps)        return a.y<b.y;    return a.x<b.x;}bool on_segment(point pi,point pj,point pk)//判斷點pk時候線上段pi, pj上{    if(xmulit(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=xmulit(p3,p4,p1);    double d2=xmulit(p3,p4,p2);    double d3=xmulit(p1,p2,p3);    double d4=xmulit(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;}int inpoto(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 = po[i];        d = po[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在多邊形外。}point mid(point &a,point &b){    point c;    c.x=(a.x+b.x)/2;    c.y=(a.y+b.y)/2;    return c;}double find_ans(){    point a,b;    int i,j,k,pos=0;    double ans=0;    po[n]=po[0];    for(i=0;i<n;i++)    {        if(one_line(temp.a,temp.b,po[i],po[i+1]))        {          rec[pos++]=po[i];          rec[pos++]=po[i];          continue;        }        if(across(temp.a,temp.b,po[i],po[i+1]))        {          temp1.a=po[i],temp1.b=po[i+1];          rec[pos++]=intersection(temp,temp1);        }    }    sort(rec,rec+pos,cmp);    for(i=0;i<pos-1;i++)    {       if(inpoto(mid(rec[i],rec[i+1])))          ans+=dis(rec[i],rec[i+1]);    }    return ans;}int main(){    int i,j,k;    while(scanf("%d%d",&n,&m))    {        if(m==0 && m==0)        return 0;        for(i=0;i<n;i++)        scanf("%lf%lf",&po[i].x,&po[i].y);        for(i=0;i<m;i++)        {            scanf("%lf%lf%lf%lf",&temp.a.x,&temp.a.y,&temp.b.x,&temp.b.y);            printf("%.3lf\n",find_ans());        }    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.