Sicily 1004. I Conduit!

本文介绍了一种处理线段交集问题的算法,包括如何通过自定义比较函数对线段进行排序,并且详细解释了如何判断不同线段是否位于同一直线上,以及在同一直线上的线段如何计算交集数量。

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

题目链接在此

参考的是这位大神的解题方法

这题要考虑的情况有很多。

另外两个double类型数据不能简单地以==来判断相等!


以下是源代码:

#include<iostream>
#include<cmath>
#include<algorithm>

using namespace std;

#define INFINITE 10000.00

bool equal(double a, double b) {  //两个double类型数据不能简单地以==来判断相等
	return fabs(a - b) < 1e-6;
}

struct line {
	double k, b;
	double x1, y1, x2, y2;

	line() {}
	line(double xx1, double yy1, double xx2, double yy2, double kk, double bb)
		: x1(xx1), y1(yy1), x2(xx2), y2(yy2), k(kk), b(bb) {}

	//  对线段(x1,y1)-(x2,y2)转化成 y=kx+b 形式,进行排序,按照 k 升序排序,如果 k 值相等,则按 b 值升序排序,
	//  如果 k,b都相等,则按 x1 升序排序,若 x1 还相等的话,则按 x2 升序排序。
	//  要对 平行于 y轴,即斜率不存在的线段 加以判断,
	//  先按照 b 值(b==x1)升序排序,再按 y1 升序排序,最后按 y2 升序排序
	bool operator<(const line& other) const{ //  自定义比较函数
		if (equal(k, other.k)){
			if (equal(k, INFINITE)) {
				if (equal(b, other.b)) {
					if (equal(y1, other.y1))
						return y2 < other.y2;
					else
						return y1 < other.y1;
				}
				else
					return b < other.b;
			}
			else if (equal(b, other.b)) {
				if (x1 == other.x1)
					return x2 < other.x2;
				else
					return x1 < other.x1;
			}
			else
				return b < other.b;
		}
		else
			return k<other.k;
	}
} s[10000];

int main() {
	int lineNum;
	double x1, y1, x2, y2;
		
	while (cin >> lineNum && lineNum != 0) {
		for (int i = 0; i < lineNum; i++) {
			cin >> x1 >> y1 >> x2 >> y2;
			if (x1 > x2 || (equal(x1, x2) && y1 > y2)) {  //保证x1<x2或斜率不存在时有y1<y2
				swap(x1, x2); 
				swap(y1, y2); 
			}

			if (equal(x1, x2))
				s[i] = line(x1, y1, x2, y2,INFINITE,x1);
			else {
				s[i] = line(x1, y1, x2, y2, (y2 - y1) / (x2 - x1), 0);
				s[i].b = y1 - s[i].k * x1;
			}
		}

		sort(s, s + lineNum);

		int counter = 1;
		double farX = s[0].x2, farY = s[0].y2;  //(farX,farY)记录当前线段的终点
		for (int i = 1; i < lineNum; i++) {
			//如果k 或者b 不相等,则肯定不在同一直线上
			if (!equal(s[i].k, s[i - 1].k) || !equal(s[i].b, s[i - 1].b)) {
				farX = s[i].x2;
				farY = s[i].y2;
				counter++;
			}
			//在同一直线上但没有公共部分
			else if ((s[i].k != INFINITE && s[i].x1 > farX) || (s[i].k == INFINITE && s[i].y1 > farY)) {
				farX = s[i].x2;
				farY = s[i].y2;
				counter++;
			}
			//在同一直线上而且有公共部分,如果当前线段的终点更远,那也要更新(x,y)
			else if ((s[i].k != INFINITE && farX < s[i].x2) || (s[i].k == INFINITE && farY < s[i].y2)) {
				farX = s[i].x2;
				farY = s[i].y2;
			}
		}

		cout << counter << endl;
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值