Segments POJ3304(计算几何+叉乘的应用)

本文介绍了一种算法,用于判断给定的二维空间线段集合中是否存在一条直线,使得所有线段投影到该直线上至少有一点重合。通过列举线段端点组合,利用向量运算来验证这一条件。

SegmentsPOJ - 3304

Given n segments in the two dimensional space, write a program, which determines if there exists a line such that after projecting these segments on it, all projected segments have at least one point in common.

Input

Input begins with a number T showing the number of test cases and then, T test cases follow. Each test case begins with a line containing a positive integer n ≤ 100 showing the number of segments. After that, n lines containing four real numbers x1y1x2y2 follow, in which (x1, y1) and (x2, y2) are the coordinates of the two endpoints for one of the segments.

Output

For each test case, your program must output "Yes!", if a line with desired property exists and must output "No!" otherwise. You must assume that two floating point numbers a and b are equal if |a - b| < 10-8.

Sample Input
3
2
1.0 2.0 3.0 4.0
4.0 5.0 6.0 7.0
3
0.0 0.0 0.0 1.0
0.0 1.0 0.0 2.0
1.0 1.0 2.0 1.0
3
0.0 0.0 0.0 1.0
0.0 2.0 0.0 3.0
1.0 1.0 2.0 1.0
Sample Output
Yes!
Yes!
No!
分析:
1.如果有一条直线通过所有的线段,那么这条直线的垂线就是答案

2.在所有线段端点所确定的直线里面,一定存在答案,如果不存在,那么就输出“No!”

关于上面两点简单证明一下:

1.垂足就满足题目条件

2.假设有一条通过所有线段的直线,那么小心的平移之,总可以与一个线段的端点重合,那么以这个端点为中心,小心的旋转直线,总可以正好过另一个端点,可能是这条线段的,也很可能是其他线段的,那么这个时候,这条仍然过所有线段的直线就过两个端点了

枚举思路:

先枚举同一条线段上的两个端点,在枚举两条线段上的端点的组合,而且注意如果两个端点是重点(横纵坐标都小于1e-8),那么就放掉这种情况,因为一个点是没办法确定一条直线

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-8;
struct Vector{
	double x,y;
	Vector(){}
	Vector(double x,double y):x(x),y(y){}
};
typedef Vector point;
Vector operator + (Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);};
Vector operator - (Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);};
Vector operator * (Vector a,Vector b){return Vector(a.x*b.x,a.y*b.y);};
Vector operator / (Vector a,Vector b){return Vector(a.x/b.x,a.y/b.y);};
double dot(Vector a,Vector b){
	return a.x*b.x+a.y*b.y;
}
double cross(Vector a,Vector b){
	return a.x*b.y-a.y*b.x;
}
struct segment{
	point p1,p2;
	segment(){}
	segment(point p1,point p2):p1(p1),p2(p2){} 
}ss[110];
int main(){
	int t;cin>>t;
	while(t--){
		int n;cin>>n;
		for(int i=0;i<n;i++){
			cin>>ss[i].p1.x>>ss[i].p1.y>>ss[i].p2.x>>ss[i].p2.y;
		}
		int flag=0;
		for(int i=0;i<n;i++){
			if(abs(ss[i].p1.x-ss[i].p2.x)<eps&&abs(ss[i].p1.y-ss[i].p2.y)<eps)continue;
			flag=1;
			Vector v=ss[i].p1-ss[i].p2;
			for(int j=0;j<n;j++){
				if(j==i)continue;
				Vector v1=ss[j].p1-ss[i].p2,v2=ss[j].p2-ss[i].p2;
				if(cross(v1,v)*cross(v2,v)>eps){
					flag=0;
					break;
				}
			} 
		}
		if(flag){
			cout<<"Yes!"<<endl;
			continue;
		}
		for(int i=0;i<n;i++){
			for(int j=i+1;j<n;j++){
				point p11=ss[i].p1,p12=ss[i].p2,p21=ss[j].p1,p22=ss[j].p2;
				if(abs(p11.x-p21.x)>eps&&abs(p11.y-p21.y)>eps){
					Vector v=p11-p21;
					flag=1;
					for(int k=0;k<n;k++){
						if(k==i||k==j)continue;
						Vector v1=ss[k].p1-p21,v2=ss[k].p2-p21;
						if(cross(v1,v)*cross(v2,v)>eps){
							flag=0;
							break;
						}
					}
					if(flag)break;
				}
				if(abs(p11.x-p22.x)>eps&&abs(p11.y-p22.y)>eps){
					Vector v=p11-p22;
					flag=1;
					for(int k=0;k<n;k++){
						if(k==i||k==j)continue;
						Vector v1=ss[k].p1-p22,v2=ss[k].p2-p22;
						if(cross(v1,v)*cross(v2,v)>eps){
							flag=0;
							break;
						}
					}
					if(flag)break;
				}
				if(abs(p12.x-p21.x)>eps&&abs(p12.y-p21.y)>eps){
					Vector v=p12-p21;
					flag=1;
					for(int k=0;k<n;k++){
						if(k==i||k==j)continue;
						Vector v1=ss[k].p1-p21,v2=ss[k].p2-p21;
						if(cross(v1,v)*cross(v2,v)>eps){
							flag=0;
							break;
						}
					}
					if(flag)break;
				}
				if(abs(p12.x-p22.x)>eps&&abs(p12.y-p22.y)>eps){
					Vector v=p12-p22;
					flag=1;
					for(int k=0;k<n;k++){
						if(k==i||k==j)continue;
						Vector v1=ss[k].p1-p22,v2=ss[k].p2-p22;
						if(cross(v1,v)*cross(v2,v)>eps){
							flag=0;
							break;
						}
					}
					if(flag)break;
				}
			}
			if(flag)break;
		}
		if(flag){
			cout<<"Yes!"<<endl;
			continue;
		}
		cout<<"No!"<<endl;
	}
	return 0;
}

设计和实现一个用于可视化计算几何算法的系统,需要从系统架构、功能模块、用户交互方式、算法实现与动画展示等多个方面进行综合考虑。以下是该系统的设计与实现方法。 ### 系统架构设计 可视化系统的整体架构可以分为以下几个核心模块: 1. **用户界面(UI)模块**:负责提供图形化操作界面,包括算法选择、参数设置、输入数据编辑、执行控制等。 2. **算法逻辑模块**:封装各种计算几何算法的核心实现,如凸包算法、Voronoi图生成、线段求交检测(如Bentley-Ottmann算法)等[^4]。 3. **可视化渲染模块**:基于图形库(如OpenGL、Pygame、Matplotlib或WebGL)实现二维或三维空间中几何结构的动态绘制。 4. **事件处理与交互模块**:支持鼠标点击、拖拽、缩放等交互操作,使用户能够直观地操控输入数据或观察过程。 5. **动画控制模块**:将算法执行过程拆解为多个步骤,并通过帧控制实现动画演示,便于教学和理解。 ### 功能模块实现 #### 1. 用户界面设计 - 使用现代GUI框架(如Tkinter、PyQt、Electron)构建交互界面 - 提供下拉菜单或按钮组选择不同的计算几何问题 - 支持手动输入点集、线段、多边形等几何对象 - 显示当前操作状态与中间结果 #### 2. 算法实现示例 以Bentley-Ottmann算法为例,其核心在于事件队列与扫描线结构的维护: ```python class BentleyOttmann: def __init__(self, segments): self.segments = segments self.events = [] # 事件队列 self.sweep_line = BalancedBST() # 扫描线结构(平衡二搜索树) def process_events(self): while self.events: event = self.events.pop(0) if event.is_intersection: self.handle_intersection(event) else: self.handle_endpoint(event) ``` #### 3. 可视化与动画实现 使用Python的turtle模块可以实现简单的递归算法可视化,例如绘制二树的过程[^3]: ```python def draw_tree(tur, step, angle): if step > 80: tur.right(angle) tur.forward(step) draw_tree(tur, step - 20, angle) tur.back(step) tur.left(2 * angle) tur.forward(step) draw_tree(tur, step - 20, angle) tur.back(step) tur.right(angle) # 初始化turtle绘图环境 tur = turtle.Turtle() tur.speed(5) tur.pensize(3) tur.pencolor('green') draw_tree(tur, 160, 24) turtle.done() ``` 对于更复杂的计算几何问题,建议采用以下技术栈: - 前端:React + D3.js 或 Three.js(三维场景) - 后端:Python Flask / Django + Shapely(几何处理库) - 数据结构:NumPy数组存储坐标信息,SciPy优化数值计算 ### 教学与实践模式支持 系统应提供两种使用模式: - **教学模式**:自动播放算法执行过程,逐帧展示每一步的几何变化,辅以文字说明和高亮标记关键结构。 - **实践模式**:允许用户自定义输入数据(如添加/删除点、线段),并实时更新可视化结果,记录操作历史以便回放与调试。 ### 性能优化策略 随着几何数据规模的增长,系统性能可能成为瓶颈。可采取以下优化措施: - 使用空间索引结构(如R树、网格划分)加速邻近查询 - 对大规模数据采用Web Worker或多线程处理避免UI冻结 - 利用GPU加速渲染复杂几何体(如Marching Cubes算法在医学影像中的应用)[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值