Poj2653
不知道你有没有玩过挑棍子的游戏,这道题就是相当于从天上按顺序扔几个棍子下来,问最上层的棍子是哪几个(为了显得不那么Low,下面把棍子换成线段)
解:没错,它考得还是叉积,话说既然这玩意儿这么有用数学老师讲课的时候怎么从来没提过呢。(小月月:别逗了你们目测法看线段相交还用叉积?)
首先构造一个队列,其中放的是当前仍然在最上层的线段,然后用当前线段去与当前队列中的线段“发生关系”,一旦相交,取而代之。这里的队列用类似链表的实现会更为便捷,因为链表这种数据结构非常方便插入,并且比较省空间。但是说真的不要一提到链表就用指针,写起来真心无力,不如用数字代替内存地址,更清晰也更方便静态查错。(这不代表用指针写不好,只是复杂一些,网络流用指针写速度谁跑得过)
#include<iostream>
#include<cstdio>
#define MAXN 101000
#define eps 1e-10
using namespace std;
struct point{
double x,y;
point(){x=y=0;}
point(double _x,double _y){x=_x; y=_y;}
};
struct list{
bool is_top;
point s,e;
int prev,next;
list(){
is_top=0;
prev=next=0;
}
}T[MAXN];int head;
point V(point start,point end){return point(end.x-start.x,end.y-start.y);}
double Cross(point a,point b){return a.x*b.y-b.x*a.y;}
bool cover(list a,list b){
return (Cross(V(a.s,a.e),V(a.s,b.s))*Cross(V(a.s,a.e),V(a.s,b.e))<-eps)
&&(Cross(V(b.s,b.e),V(b.s,a.s))*Cross(V(b.s,b.e),V(b.s,a.e))<-eps);
}int n;
int main(){
// freopen("poj.in","r",stdin);
double a,b,c,d;
while(scanf("%d",&n)&&n){
head=0;
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf%lf",&T[i].s.x,&T[i].s.y,&T[i].e.x,&T[i].e.y);
T[i].is_top=1; T[i].next=0; T[i].prev=head; T[head].next=i;
for(int j=head;j;j=T[j].prev)
if(cover(T[j],T[i])){
T[j].is_top=0;
T[T[j].prev].next=T[j].next;
T[T[j].next].prev=T[j].prev;
}head=i;
}
printf("Top sticks:");
for(int i=1;i<n;i++) if(T[i].is_top) printf(" %d,",i);
printf(" %d.\n",n);
}
return 0;
}