Pick-up sticks POJ - 2653(判断线段覆盖)

博客介绍了POJ 2653题目的解决方案,涉及判断线段覆盖的问题。通过使用队列,将未被覆盖的线段存储,并在放入新线段时逐一比较,确定线段是否被新线段覆盖。最终留在队列中的线段即为未被覆盖的部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出n个线段,后来的盖在先来的上面如果这俩线段相交的话,问最后有多少线段没被覆盖。

思路:拿一个队列把已经放上去且没有被覆盖的线段丢进去,然后当一个线段放上来后将队列中的线段一个个拿出来对比,如果被新来的覆盖了就不管它了,如果对比后没有被覆盖那么还乖乖在push进去,对比完一轮以后就把这个新的也push进去,往复循环最后剩在队列中的就是没有被覆盖的。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#define eps 1e-8
using namespace std;


double sgn(double x) {
	if(fabs(x) < eps)return 0;
	if(x < 0) return -1;
	return 1;
}

struct Point { // 表示点
	double x, y;
	Point(){}
	Point(double _x,double _y) {
		x = _x; y = _y;
	}
	Point operator + (const Point& b) const {
		return Point(x + b.x,y + b.y);
	}
	Point operator - (const Point &b) const {
		return Point(x - b.x,y - b.y);
	}
	double operator * (const Point &b) const {
		return x*b.x + y*b.y;
	}
	double operator ^ (const Point &b) const {
		return x*b.y - y*b.x;
	}
};

struct Line { // 表示线段
	Point s,e;
	Line(){}
	Line(Point _s,Point _e) {
		s = _s;e = _e;
	}
	
	//线段与线段相交判断
	//2 规范相交
	//1 非规范相交
	//0 不相交
	int seg_cross_seg(Line v){
		int d1 = sgn((e-s)^(v.s-s));
		int d2 = sgn((e-s)^(v.e-s));
		int d3 = sgn((v.e-v.s)^(s-v.s));
		int d4 = sgn((v.e-v.s)^(e-v.s));
		if((d1^d2)==-2&&(d3^d4)==-2) return 2;
		return (d1==0 &&sgn((v.s-s)*(v.s-e))<=0)||
				(d2==0 &&sgn((v.e-s)*(v.e-e))<=0)||
				(d3==0 &&sgn((s-v.s)*(s-v.e))<=0)||
				(d4==0 &&sgn((e-v.s)*(e-v.e))<=0);
	}
	
	int relation(Point p){
			int c=sgn((p-s)^(p-e));
			if(c<0)return 1;
			else if(c>0) return 2;
			else return 3;
		}
		bool parallel(Line v){
			return sgn((e-s)^(v.e-v.s))==0;
		}
		//直线与直线相交判断
		//0 平行
		//1 重合
		//2 相交
		int line_cross_line(Line v){
			if((*this).parallel(v))
			return v.relation(s)==3;
			return 2;
		}
} l[100005];

int n;
queue <pair <Line, int> > q;

int main() {	
	while(~scanf("%d", &n) && n) {
		double x[2], y[2];
		for(int i = 1;i <= n; i++) {
			scanf("%lf %lf %lf %lf", &x[0], &y[0], &x[1], &y[1]);
			l[i] = Line(Point(x[0], y[0]), Point(x[1], y[1]));
		}
		q.push({l[1], 1});
		
		for(int i = 2;i <= n; i++) {
			int size = q.size();
			while(size--) {
				pair <Line, int> now = q.front(); q.pop();
				int res = now.first.seg_cross_seg(l[i]);
				if(res == 0) {
					q.push(now);
				}
			}
			q.push({l[i], i});
		}
		
		printf("Top sticks: ");
		while(!q.empty()) {
			pair <Line, int> res = q.front(); q.pop();
			printf("%d", res.second);
			printf("%s", q.empty()?".": ", ");
		}
		puts("");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值