1. 程式人生 > >hdu 1147 Pick-up sticks (判斷線段是否相交)

hdu 1147 Pick-up sticks (判斷線段是否相交)

題目連結:hdu 1147

題意:給你n條棒,按輸入順序投放,問最後哪些棒是最上面的,輸出它們,保證輸出最多不超過1000。

題解:用set容器來存放滿足條件的棒。詳情見程式碼。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<cmath>

using namespace std;

const int maxn=100010;

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

struct Line{
    point a,b;
    Line(){}
    Line(point _a,point _b){
        a=_a;b=_b;
    }
}line[maxn];

point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,double p) { return point(a.x*p,a.y*p);}
point operator / (point a,double p){ return point(a.x/p,a.y/p);}

bool operator < (const point &a,const point &b){
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}

double Cross(point a,point b){ return a.x*b.y-a.y*b.x;}
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表示,相交於端點也認定為相交
//    printf("c1=%f,c2=%f,c3=%f,c4=%f\n",c1,c2,c3,c4);
    if(dcmp(c1*c2)>=0&&dcmp(c3*c4)>=0) return true;

    return false;
}

set<int> myset;
set<int> ::iterator it,it2;

int storage[1100];
int main()
{

    int n;
    while(~scanf("%d",&n)&&n)
    {
        double x1,y1,x2,y2;

        myset.clear();
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[i]=Line(point(x1,y1),point(x2,y2));
        }

        myset.insert(0); ///第一條棒存進去
        for(int i=1;i<n;i++)
        {
            bool flag=true;
            int tot=0;
            for(it=myset.begin();it!=myset.end();it++) ///與之前頂部棒判斷是否有相交
            {
                int item=*it;
                if(isCross(line[i].a,line[i].b,line[item].a,line[item].b)){
//                        printf("i=%d,item=%d\n",i,item);
                    storage[tot++]=*it; ///有交叉,記錄下來
                }
            }

            myset.insert(i); ///最後的肯定不會被相交,故放進去
            for(int j=0;j<tot;j++){
                myset.erase(storage[j]); ///刪除容器內被相交的
            }
        }
//        printf("%d\n",myset.size());
        printf("Top sticks:");
        it2=myset.end();
        it2--;
        for(it=myset.begin();it!=it2;it++)
            printf(" %d,",*it+1);
        printf(" %d.\n",*(myset.rbegin())+1);
    }
    return 0;
}