1. 程式人生 > >【POJ-2653-Pick-up sticks】計算幾何+STL

【POJ-2653-Pick-up sticks】計算幾何+STL

題目連結
http://poj.org/problem?id=2653
題意

n
, n < = 1 e 5 , < = 1000 在一個二維平面上依次放置n條木棍,問最後沒有被覆蓋的木棍有哪些,n<=1e5,答案<=1000
做法
我們時光倒流一下,從後往前做這道題
很明顯最後一根木棍一定是在最上面的,那麼這條木棍所覆蓋的木棍一定都是被覆蓋的
依次遞推就能求出所有被最後一條木棍直接覆蓋或者間接覆蓋的木棍
然後繼續向前掃描到一個沒有被覆蓋的木棍,然後重複這個過程
v i s 這樣就可以得到所有在最頂層的木棍,如果我們用vis標記被覆蓋木棍的方法
n 2 時間複雜度為n^2
l i s t l i s t O ( n 1000 ) 但是如果我們用list裡面的list維護沒有被覆蓋的木棍,時間複雜度就是O(n*1000)。
程式碼

#include<stdio.h>
#include<math.h>
#include<queue>
#include<list>
#include<iostream>
#include<algorithm>
using namespace std;
const  double eps = 1e-12;
const  double pi = acos(-1.0);
const int maxp = 1010;
int sgn( double x)
{
    if (fabs(x) <eps) return 0;
    if(x <0) return -1;
    return 1;
}
struct Point
{
    double x, y;
    Point() {}
    Point ( double _x,  double _y)
    {
        x = _x, y = _y;
    }
    bool operator == (Point b) const
    {
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
    }
    bool operator < (Point b) const
    {
        return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
    }
    Point operator - (const Point &b) const
    {
        return Point(x - b.x, y - b.y);
    }
    //叉積  |a||b|sin
    double  operator ^ (const Point &b) const
    {
        return x * b.y - y * b.x;
    }
    //點積 |a||b|cos 向量點積之後反過來求夾角
    double  operator * (const Point & b) const
    {
        return x * b.x + y * b.y;
    }
    Point operator + (const Point &b) const
    {
        return Point(x + b.x, y + b.y);
    }
};
struct Line
{
    Point s, e;
    Line() {}
    Line(Point _s, Point _e)
    {
        s = _s, e = _e;
    }
    //兩線段相交判斷
    //2 規範相交
    //1 非規範相交-過端點
    //0 不相交
    int segcrossseg(Line v)
    {
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        int d3 = sgn((v.e-v.s)^(s-v.s));
        int d4 = sgn((v.e-v.s)^(e-v.s));
        if((d1^d2)==-2&&(d3^d4)==-2) return 2;
            return ((d1==0&&sgn((v.s-s)*(v.s-e))<=0)||(d2==0&&sgn((v.e-s)*(v.e-e))<=0)||(d3==0&&sgn((s-v.s)*(s-v.e))<=0)||(d4==0&&sgn((e-v.s)*(e-v.e))<=0));
    }
};
const int maxn = 1e5+10;
Line l[maxn];
vector<int>ans;
list<int> L;
void del(list<int>::iterator it)//遞迴算出所有被當前線段所影響的線段
{
    Line now = l[*it];
    list<int>::iterator tmp=it;
    for(list<int>::iterator itt=(++it);itt!=L.end();)
    {
         Line nex = l[*itt];
         if(now.segcrossseg(nex))
         {
             del(itt);//找到之後先遞迴,再將本點刪除
             itt=L.erase(itt);
         }
         else ++itt;
    }
    return ;
}
int main()
{
    int n;
    double xa,xb,ya,yb;
    while(scanf("%d",&n)!=EOF)
    {
        L.clear();
        ans.clear();
        if(n==0) break;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
            l[i]=Line (Point(xa,ya),Point(xb,yb));
        }
        for(int i=n;i>=1;i--)
        {
            L.push_back(i);
        }
        for(list<int>::iterator it=L.begin();it!=L.end();)
        {
            list<int>::iterator tmp=it;
            del(it);
            it=++tmp;//由於有刪除操作,要先存當前指標位置,在刪除之後讓迭代器指向當前的下一位
        }
        L.reverse();
        for(list<int>::iterator it=L.begin();it!=L.end();++it)
        {
            int tmp=*it;
            ans.push_back(tmp);
        }
         sort(ans.begin(),ans.end());//保證答案有序
         printf("Top sticks:");
        for(int i=0;i<ans.size();i++)
        {
            if(i!=ans.size()-1) printf(" %d,",ans[i]);
            else printf(" %d.\n",ans[i]);
        }
    }
    return 0;
}