计算几何--判断两条线段相交--poj 2653

Pick-up sticks
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 8862 Accepted: 3262

Description

Stan has n sticks of various length. He throws them one at a time on the floor in a random way. After finishing throwing, Stan tries to find the top sticks, that is these sticks such that there is no stick on top of them. Stan has noticed that the last thrown stick is always on top but he wants to know all the sticks that are on top. Stan sticks are very, very thin such that their thickness can be neglected.

Input

Input consists of a number of cases. The data for each case start with 1 <= n <= 100000, the number of sticks for this case. The following n lines contain four numbers each, these numbers are the planar coordinates of the endpoints of one stick. The sticks are listed in the order in which Stan has thrown them. You may assume that there are no more than 1000 top sticks. The input is ended by the case with n=0. This case should not be processed.

Output

For each input case, print one line of output listing the top sticks in the format given in the sample. The top sticks should be listed in order in which they were thrown. 

The picture to the right below illustrates the first case from input.

Sample Input

5
1 1 4 2
2 3 3 1
1 -2.0 8 4
1 4 8 2
3 3 6 -2.0
3
0 0 1 1
1 0 2 1
2 0 3 1
0

Sample Output

Top sticks: 2, 4, 5.
Top sticks: 1, 2, 3.

Hint

Huge input,scanf is recommended.

Source


题意:
          依次给出n条线段,后添的线段若与先前的线段相交,则会覆盖先前的线段,问最后会有多少天线段,输出所能看见线段的下标。。。。。
          判断两条线段相交
思路:
         判断线段AB与线段CD是否相交;
         1:以线段AB,线段CD为对角线所构成的矩形相交,则继续判断;(用以排除两线段同线但不相交的情况)
         2:用叉积运算判断点A,B是否在线段CD两侧,判断点C,D是否在线段AB两侧,若符合,则两先段相交!
代码:
#include "cstdio"
#include "cmath"
#include "vector"
#include "iostream"

using namespace std;
const double eps = 1e-8;

double max(double a,double b){ return a>b?a:b; }
double min(double a,double b){ return a<b?a:b; }

int cmp(double x){
    if(fabs(x)<eps) return 0;
    if(x>0) return 1;
    return -1;
}

inline double sqr(double x){
    return x*x;
}

struct point{   //点结构体
    double x,y;
    point(){}
    point (double a,double b):x(a),y(b) {} //重载
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    friend point operator + (const point a,const point b){
        return point(a.x+b.x,a.y+b.y);
    }
    friend point operator - (const point a,const point b){
        return point(a.x-b.x,a.y-b.y);
    }
};

double det(const point &a,const point &b){   //向量a与向量b的叉积
    return a.x*b.y-a.y*b.x;
}

struct line{   //线结构体
    point a,b;
    line(){}
    line(point x,point y):a(x),b(y){}
};

bool line_make_point_one(line a,line b){   //判断两线段是否相交,完美代码!
    return
        max(a.a.x,a.b.x) >= min(b.a.x,b.b.x) &&  //前四行判断两向量所形成的矩形是否相交,排除两线段在同一条直线但不相交的可能
        max(b.a.x,b.b.x) >= min(a.a.x,a.b.x) &&
        max(a.a.y,a.b.y) >= min(b.a.y,b.b.y) &&
        max(b.a.y,b.b.y) >= min(a.a.y,a.b.y) &&
        cmp(det(a.a-b.b,b.a-b.b))*cmp(det(a.b-b.b,b.a-b.b))<=0 &&  //判断两线段是否相交
        cmp(det(b.a-a.a,a.b-a.a))*cmp(det(b.b-a.a,a.b-a.a))<=0;
}

int main(){
    int n;
    while(scanf("%d",&n),n!=0)
    {
        line a;
        vector<line> p;  //线段向量
        vector<int> v;  //记录线段向量的下标
        p.clear();
        v.clear();

        scanf("%lf %lf %lf %lf",&a.a.x,&a.a.y,&a.b.x,&a.b.y);
        p.push_back(a);
        v.push_back(1);
        for(int k=2;k<=n;++k)
        {
            scanf("%lf %lf %lf %lf",&a.a.x,&a.a.y,&a.b.x,&a.b.y);
            for(int i=0; i<(int)p.size(); ++i)
            {
                bool flag = line_make_point_one(a,p[i]);
                if(flag==true)
                {
                    p.erase(p.begin()+i);
                    v.erase(v.begin()+i);
                    i--;
                }
            }
            p.push_back(a);
            v.push_back(k);
        }
        printf("Top sticks:");
        int i;
        for( i=0; i<(int)v.size()-1; ++i)
            printf(" %d,",v[i]);
        printf(" %d.\n",v[i]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值