POJ 1228 穩定凸包

題意:給出n個點,這n個點在凸包的邊上或者點上。問僅由這 幾個點能否確定凸包的形狀。。

思路:考慮什麼情況下不能是穩定的凸包,就是某個邊上只有兩個點,然後再往外面擴一個就可以形成一個新的凸包,如果邊上還有一個點的話, 那麼就不能添加新的點,因爲給出的點是保證在凸包上的。。

凸包的模板跟之前的一題有點區別,就是對於共線的點是否加入凸包,正常的時候是不加入的(因爲如果沒什麼要求的話加進去也沒有用。。),但是這次需要判斷中間是否有點,所以就加進去了(其實是別的題解加進去了2333),然後最後一條邊上的點沒有被加進,這不是因爲求凸包的算法執行的時候的原因,是因爲排序的原因,當最後一條線經過多個點的時候,會先連接距離近的點,所以找遠的點的時候就會不滿足左旋,把當前點彈出去。。

對於這道題的判斷條件,就是那個judge函數,返回false的情況就是i-1,i,i+1,i+2形成了三條折線,這樣i和i+1之間就沒有點了,就不滿足退出= =

代碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<list>
using namespace std;
const double INF = 1e200;
const double EP = 1e-10;
const int maxn = 1100;
const double PI = acos(-1);
struct POINT{///點 定義
    double x;
    double y;
    POINT(double a = 0,double b = 0){x = a;y = b;}
};
struct SEGMENT{///line segment///線段 定義
    POINT s;
    POINT e;
    SEGMENT(POINT a,POINT b){s = a;e = b;}
    SEGMENT(){}
};
struct LINE{///ax + by + c = 0&&a >= 0///一般式
    double a;
    double b;
    double c;
    LINE(double da,double db,double dc){a = da;b = db;c = dc;}
    LINE(double x1,double y1,double x2,double y2){///根據兩個點求出一般式
        a = y1 - y2;b = x2 - x1;c = x1*y2 - x2*y1;
        if(a < 0){a*=-1;b*=-1;c*=-1;}
    }
};
double multiply(POINT sp,POINT ep,POINT op){///向量op->sp X op->ep的叉乘,小於0:ep在op->sp順時針方向//大於0:ep在op->sp逆時針方向//等於0:三點共線
    return ((sp.x - op.x)*(ep.y - op.y) - (ep.x - op.x)*(sp.y - op.y));
}
double dotmultiply(POINT p1,POINT p2,POINT p0){
    return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y));
}
bool online(SEGMENT l,POINT p){///判斷點是否在線段上
    return ((multiply(l.e,p,l.s) == 0)&&(((p.x-l.s.x)*(p.x-l.e.x))<= 0)&&(((p.y-l.s.y)*(p.y-l.e.y)) <= 0));
}
bool intersect(SEGMENT u,SEGMENT v){///兩線段相交(包括端點),返回true
    return ((max(u.s.x,u.e.x) >= min(v.s.x,v.e.x))&&
            (max(v.s.x,v.e.x) >= min(u.s.x,u.e.x))&&
            (max(u.s.y,u.e.y) >= min(v.s.y,v.e.y))&&
            (max(v.s.y,v.e.y) >= min(u.s.y,u.e.y))&&
            (multiply(v.s,u.e,u.s)*multiply(u.e,v.e,u.s) >= -EP)&&
            (multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s) >= -EP));
}
bool intersect_a(SEGMENT u,SEGMENT v){///兩線段相交(不包括端點)
    return ((intersect(u,v))&&
            !online(u,v.s)&&
            !online(u,v.e)&&
            !online(v,u.e)&&
            !online(v,u.s));
}
int lineintersect(LINE l1,LINE l2,POINT &p){///求兩直線交點,有交點返回1和交點,沒有返回0,重合返回2
    double d = l1.a*l2.b-l2.a*l1.b;
    double d2 = l1.a*l2.c-l2.a*l1.c;
    double d3 = l1.b*l2.c-l2.b*l1.c;
    if(fabs(d) < EP&&fabs(d2) < EP&&fabs(d3) < EP)return 2;
    p.x = (l2.c*l1.b-l1.c*l2.b)/d;
    p.y = (l2.a*l1.c-l1.a*l2.c)/d;
    if(fabs(d) < EP)return 0;
    return 1;
}
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 top;///凸包的頂點個數
POINT p[maxn],stack[maxn];
bool top_cmp(POINT a,POINT b){
    double k = multiply(a,b,p[0]);
    if(k > 0)return 1;
    if(k < 0)return 0;
    return dis(a,p[0]) < dis(b,p[0]);
}
void graham(int n){
    top = 1;
    int k = 0;
    for(int i = 1;i < n;i ++)
        if(p[i].y < p[k].y||((p[i].y == p[k].y)&&(p[i].x < p[k].x)))
            k=i;
    swap(p[0],p[k]);
    sort(p+1,p+n,top_cmp);
    stack[0] = p[0],stack[1] = p[1];
    for(int i = 2;i < n;i ++){
        while(top >= 1&&multiply(p[i],stack[top],stack[top-1]) > 0)top --;
        stack[++top] = p[i];
    }
}
///******************凸包結束****************

///*********************************************************************************
bool judge(){
    for(int i = 1;i < top;i ++){
        if(multiply(stack[i-1],stack[i+1],stack[i])&&multiply(stack[i],stack[i+2],stack[i+1]))return false;
    }
    return true;
}
int main(){
    //freopen("in.txt","r",stdin);
    int T;//stack
    cin>>T;
    while(T --){
        int n;
        cin>>n;
        for(int i = 0;i < n;i ++){
            int a,b;
            cin>>a>>b;
            p[i].x = a;
            p[i].y = b;
        }
        if(n < 6){
            puts("NO");
            continue;
        }
        graham(n);
        if(judge())puts("YES");
        else puts("NO");
    }
    return 0;
}

發佈了140 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章