1. 程式人生 > >zoj 1010 Area (叉積求面積 與 跨立相交實驗判斷相交)

zoj 1010 Area (叉積求面積 與 跨立相交實驗判斷相交)

題目連結:zoj 1010

題意:給你 N  個點的座標,點是按照順序輸入的。每一個點都與它後面的那個點連成一條線段,最後一個點與起點相連。

求組成的多邊形的面積。

參考部落格:https://blog.csdn.net/freezhanacmore/article/details/10181361

 

解題思路:根據叉積的標量意義兩向量叉積得到新向量長度為這兩個所構成的平行四邊形的面積,利用這個性質我們可以求三角形的面積(除以2就好了)。

這題關鍵不在求多邊形的面積,而在於判斷這個多邊形是否合法,

這裡的不合法指的是隻要存在一條線段不和它直接首尾相連任意

一條線段相交,  就表示面積不可求,輸出 impossible

 

然後就是線段的比較判斷問題:


注意: 是要與不和當前線段直接相連的每一條線段都比較。
          那麼我們每次加入一個點,直接判斷新形成的線段與前面所有出現過的不直接相連的比較就可以了

所以應該從第三條線段開始列舉。
因為第一條線段沒有線段可以和它比較;
第二條線段前面只有一條線段,而這條線段又是和他直接相連的,所以不用比較。
這樣一直到了第 N-1 條線段都可以這麼判斷下去。

然後注意到最後一條線段

是終點和起點相連形成的,所以它不能和第一條線段比較,也不可以和第 n-1 條線段比較。

還有注意一點的是:相交於端點也要算進去

最後就是叉積求面積了。





#include<bits/stdc++.h>
using namespace std;

const int maxn=1010;
int n;

struct point
{
    double x,y;
    point() {}

    point(double _x,double _y)
    {
        x=_x;
        y=_y;
    }

    point operator -(const point &b) const {
        return point(x-b.x,y-b.y);
    }
}p[maxn];


double Cross(point a,point b) ///叉積
{
    return a.x*b.y-a.y*b.x;
}

double esp=1e-8;
int dcmp(double x)
{
    if(fabs(x)<esp) return 0;
    else return x>0?1:-1;
}
bool isCross(point s1,point e1,point s2,point e2)///判斷兩次跨立相交
{
    ///第一步,快速排斥實驗
    if(!(min(s1.x,e1.x)<=max(s2.x,e2.x)&&min(s2.x,e2.x)<=max(s1.x,e1.x)&&
       min(s1.y,e1.y)<=max(s2.y,e2.y)&&min(s2.y,e2.y)<=max(s1.y,e1.y))) return false;

    ///首先判斷向量s2e2 跨立 向量s1e1
    double c1=Cross(s2-s1,e1-s1),c2=Cross(e1-s1,e2-s1);
    ///再次判斷向量s1e1 跨立 向量 s2e2
    double c3=Cross(s1-s2,e2-s2),c4=Cross(e2-s2,e1-s2);

    ///==0表示,相交於端點也認定為相交
    if(dcmp(c1*c2)>=0&&dcmp(c3*c4)>=0) return true;

    return false;
}

bool haveCross()
{

    ///從第三條線段開始,一直到第N-1條線段
    for(int i=2;i<n-1;i++)
    {
        for(int j=1;j<i;j++)///與前面每一條不直接相連的線段
        {
            if(isCross(p[i],p[i+1],p[j-1],p[j])){
                return true;
            }
        }
    }

    ///判斷最後一條線段 p[n-1]_p[0]
    ///從第二條線段一直比較到n-2條線段
    for(int i=1;i<n-2;i++){
        if(isCross(p[n-1],p[0],p[i],p[i+1])){
            return true;
        }
    }

    return false;
}
double Area()
{
    double area=0;

    for(int i=1;i<n-1;i++)
        area+=Cross(p[i]-p[0],p[i+1]-p[0]);

    return fabs(area)/2.0;
}
int main()
{
    int ncase=0;

    while(scanf("%d",&n)&&(n!=0))
    {
        double a,b;

        for(int i=0;i<n;i++){

            scanf("%lf%lf",&a,&b);
            p[i]=point(a,b);
        }

        if(n<3) {
            printf("Figure %d: Impossible\n\n",++ncase);
            continue;
        }

        if(haveCross()){
            printf("Figure %d: Impossible\n\n",++ncase);
            continue;
        }
        else {
            printf("Figure %d: %.2f\n\n",++ncase,Area());
        }
    }

    return 0;
}