POJ 2635 Pick-up sticks (线段相交)

题意:有些人没事儿喜欢往地上任棍子,后面扔的可能盖住前面扔的,显然最后扔的那根棍子一定没被压住,求所有没有被其它棍子压住的棍子。

题解:规范相交。用链表优化下。当然也可以用队列存储下标。

#include<cmath>
#include<iostream>
using namespace std;

#define eps 1e-8
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
struct Point { double x, y; };
struct Line { Point a, b; };

struct NODE
{
	Line l;
	int id;
	NODE *next, *pre;
} node[200000];

double xmult ( Point p1, Point p2, Point p0 )
{
	return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}

int opposite_side ( Point p1, Point p2, Point l1, Point l2 )
{
	return xmult ( l1, p1, l2 ) * xmult ( l1, p2, l2 ) < -eps;
}

int intersect_ex ( Line u, Line v )
{
	if ( max(u.a.x, u.b.x) > min(v.a.x, v.b.x) &&
		 max(v.a.x, v.b.x) > min(u.a.x, u.b.x) &&
		 max(u.a.y, u.b.y) > min(v.a.y, v.b.y) &&
		 max(v.a.y, v.b.y) > min(u.a.y, u.b.y) &&
	     opposite_side ( u.a, u.b, v.a, v.b ) && 
		 opposite_side ( v.a, v.b, u.a, u.b ) )
		 return 1;
	return 0;
}

void insert ( NODE *& last, NODE *nod )
{
	nod->pre = last;
	nod->next = NULL;
	last->next = nod;
	last = nod;
}

void del ( NODE *nod )
{
	nod->next->pre = nod->pre;
	nod->pre->next = nod->next;
}

int main()
{
	int n;
	while ( scanf("%d",&n) && n )
	{  
		NODE first, *last, *p, *tmp;
		first.next = NULL;
		last = NULL;
	    
		for ( int i = 1; i <= n; i++ )
		{
			scanf("%lf %lf %lf %lf", &node[i].l.a.x, &node[i].l.a.y, &node[i].l.b.x, &node[i].l.b.y );
			node[i].id = i;

			if ( last == NULL )
			{
				last = &node[i];
				last->next = NULL;
				last->pre = &first;
				first.next = last;
				continue;
			}

			insert ( last, &node[i] );
			p = last->pre;
			while ( p != &first )
			{
				tmp = p->pre;
				if ( intersect_ex ( last->l, p->l ) )
					del ( p );
				p = tmp;
			}
		}

		printf("Top sticks: ");
		p = first.next;
		while ( p != NULL )
		{
			printf("%d",p->id);
			if ( p->next == NULL )
				printf(".\n");
			else printf(", ");
			p = p->next;
		}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值