UVa 10902 Pick-up Sticks (线段与线段相交)

题目:有n根木条,一根一根的往一个坐标系上丢(给出木条两点的坐标),问最后不被覆盖的木条有哪些,即丢的木条如果和前面丢的木条交叉的话,就会覆盖前面那根木条。


公式:p1xp2=x1*y2-x2*y1(外积),p1*p2=(x1*x2,y1*y2)(内积)

判断q是否在线段p1-p2上面,根据(p1-q)x(p2-q)=0来判断q是否在直线p1-p2上。利用内积(p1-q)*(p2-q)<0判断q是否在线段p1-p2上。

p1-p2,q1-q2的交点:

(x,y)=p1+(p2-p1)*((q2-q1)x(q1-p1)/((q2-q1)x(p2-p1)));

推理:把p1-p2直线写成点p1+t(p2-p1),然后就是点和q1-q2直线了,最后计算得出上面的。

最后验证交点在两条线段上没有。

注意:double精度问题,开始我检查了半天,才发现是精度问题。

list的remove_if函数:遍历链表,删除满足所有条件的,条件自己定义。



#include <iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<list>
using namespace std;
#define EPS 1e-10
#define N 100005

struct point
{
    double a,b;
    point(){}
    point(double a,double b):a(a),b(b){}
    point operator +(point p)
    {
        return point(p.a+a,p.b+b);
    }
    point operator -(point p)
    {
        return point(a-p.a,b-p.b);
    }
    point operator *(double p)
    {
        return point(a*p,b*p);
    }
    double dot(point p)//内积
    {
        return (p.a*a+p.b*b);
    }
    double det(point p)//外积
    {
        return (a*p.b-b*p.a);
    }
};
struct seg
{
    int i;
    point p1,p2;
};
point p1,p2;
list<seg>li;
//判断q是否在线段p1-p2上
bool on_str(point p1,point p2,point q)
{
    return (abs((p1-q).det(p2-q))<EPS&&(p1-q).dot(p2-q)<EPS);
}
//求两直线交点
point intersection(point p1,point p2,point q1,point q2)
{
    return p1+(p2-p1)*((q2-q1).det(q1-p1)/(q2-q1).det(p2-p1));
}
bool judge(const seg& s)
{
      point q1=s.p1;
      point q2=s.p2;
         if(abs((p1-p2).det(q1-q2))<EPS)//判断外积是否为0
         {
             if(on_str(p1,p2,s.p1)||on_str(p1,p2,s.p2)||on_str(s.p1,s.p2,p1)||on_str(s.p1,s.p2,p2))//判断是否有重合
              return 1;
              else
                    return 0;
         }
         else
         {
            point r=intersection(p1,p2,s.p1,s.p2);
             return on_str(p1,p2,r)&&on_str(s.p1,s.p2,r);
         }
}
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {

            li.clear();
        for(int i=1;i<=n;i++){
        scanf("%lf%lf%lf%lf",&p1.a,&p1.b,&p2.a,&p2.b);
                li.remove_if(judge);
                li.push_back(seg{i,p1,p2});
        }
        printf("Top sticks: ");
        while(li.size()>1)
        {
            printf("%d, ",li.front().i);
            li.pop_front();
        }
        printf("%d.\n",li.front().i);
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值