题意:有n条线段(编号为1n),按1n的顺序放在二维坐标系上(就是先放1号,再放2号……),要求输出最上面的那些线段的编号。(就是没有其他线段压在它上面的那些线段)
注意:有交点即为被压。
1.叉积
判断线段相交需要有关于叉积(外积,向量积)的预备知识。
若
(不用会证明)
性质:设两向量的叉积的模为x。则有:
若x>0,则的转向为逆时针。
若x=0,则两向量的方向在同一直线上。
否则,的转向为顺时针。
(证明不用会)
2.跨立实验
如图,两个向量如果相交(交点不是向量端点),
当且仅当
特别地,当两个向量的交点为一个向量的一个端点,则通过叉积大小等于0来判断。
注意:上面纯属扯淡,主要看代码。
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e4+10;
struct node{
double x,y;
};
struct line{
node p1,p2;
}list[N];
double mult(node p1,node p2,node p0)
{
double x1,y1,x2,y2;
x1=p1.x-p0.x;
y1=p1.y-p0.y;
x2=p2.x-p0.x;
y2=p2.y-p0.y;
return x1*y2-x2*y1;
}
bool check(line l1,line l2)
{
node p1=l1.p1;
node p2=l1.p2;
node p3=l2.p1;
node p4=l2.p2;
if(mult(p3,p2,p1)*mult(p2,p4,p1)>0&&mult(p1,p4,p3)*mult(p4,p2,p3)>0)return true;
if( (mult(p3,p4,p1)==0&&min(p3.x,p4.x)<=p1.x&&p1.x<=max(p3.x,p4.x)&&min(p3.y,p4.y)<=p1.y&&p1.y<=max(p3.y,p4.y)) ||
(mult(p3,p4,p2)==0&&min(p3.x,p4.x)<=p2.x&&p2.x<=max(p3.x,p4.x)&&min(p3.y,p4.y)<=p2.y&&p2.y<=max(p3.y,p4.y)) ||
(mult(p1,p2,p3)==0&&min(p1.x,p2.x)<=p3.x&&p3.x<=max(p1.x,p2.x)&&min(p1.y,p2.y)<=p3.y&&p3.y<=max(p1.y,p2.y)) ||
(mult(p1,p2,p4)==0&&min(p1.x,p2.x)<=p4.x&&p4.x<=max(p1.x,p2.x)&&min(p1.y,p2.y)<=p4.y&&p4.y<=max(p1.y,p2.y)) ) return true;
return false;
}
bool v[N];
int b[N];
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf%lf",&list[i].p1.x,&list[i].p1.y,&list[i].p2.x,&list[i].p2.y);
int tot=0;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
{
if(check(list[i],list[j]))
{
v[i]=1;
break;
}
}
for(int i=1;i<=n;i++)if(!v[i])b[++tot]=i;
for(int i=1;i<tot;i++)printf("%d ",b[i]);
printf("%d
",b[tot]);
return 0;
}/*
提供一个数据
2
0 0 0 1
0 2 0 3
*/