首页 > 其他分享 >[题解]POJ3304 Segment

[题解]POJ3304 Segment

时间:2024-07-16 11:54:29浏览次数:7  
标签:直线 return point 题解 线段 vec 端点 POJ3304 Segment

POJ3304 Segment

题意简述

多测,每次给定\(n\)条线段,请问是否能找到\(1\)条直线,使得所有线段在该直线上的投影有公共部分。

注:两点距离\(<10^{-8}\)被认为是相等的。

思路分析

题意转化一下,就是要我们找一条直线\(l_1\),穿过所有线段。这样对于任意直线\(l_2\perp l_1\),都满足题意。

我们又发现,如果存在\(l_2\),那么在规定“\(l_2\)必须穿过所有端点中的至少\(2\)个”的前提下,\(l_2\)仍然存在。

为什么呢?
image
比如这条红色直线就是我们找到的答案。
image
接下来将红色直线左移,直到“再移一下就不能穿过所有线段”为止。显然此时一定有一个端点在直线上。
image
绕这个端点旋转红色直线,直到“再旋转一下就不能穿过所有线段”位置。显然此时直线上又多了一个端点。而同时满足题目要求。

接下来枚举两两线段之间的端点,判断过这两个端点的直线是否穿过所有线段即可。

判断线段穿过直线仅需一次跨立实验。即:

  • 设有线段\(AB\),直线\(CD\)。
  • 则如果\(\vec{AC}\)与\(\vec{AD}\)的方向关系和\(\vec{BC}\)与\(\vec{BD}\)的方向关系不同,则说明\(AB\)与\(CD\)相交。否则不相交。判断两向量方向关系需要用到叉积,具体可以见[题解]UVA10902 Pick-up Sticks中对跨立实验的说明。

我们可以发现,答案如果存在,则选择的两个端点一定可以不在一条线段上。所以枚举线段时\(j\)可以从\(i+1\)开始,但相应地需要特判一下\(n=1\)的情况,直接输出Yes即可。

另外,枚举出的两个端点如果重合(即距离\(<10^{-8}\))则不应参与计算。

时间复杂度\(O(n^3)\)。

Code

POJ真的是时代的眼泪了……编译器太老了,代码需要很多修改,因此就不放修改后的较为冗长的代码了。

重在理解,所以放一份修改前、比较简洁的代码实现,注意无法通过POJ编译。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
struct point{double x,y;};
struct segment{point a,b;};
struct line{point a,b;};
double cross(point a,point b){return a.x*b.y-b.x*a.y;}
point vec(point a,point b){return {b.x-a.x,b.y-a.y};}
double dist(point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
bool intersect_line(line a,segment b){
	return cross(vec(b.a,a.a),vec(b.a,a.b))*cross(vec(b.b,a.a),vec(b.b,a.b))<=0;
}
int t,n;
segment ts[110];
bool solve(line a){
	if(dist(a.a,a.b)<1e-8) return 0;
	for(int i=1;i<=n;i++)
		if(!intersect_line(a,ts[i])) return 0;
	return 1;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++)
			cin>>ts[i].a.x>>ts[i].a.y>>ts[i].b.x>>ts[i].b.y;
		bool f=0;
		if(n==1) f=1;
		else{
			for(int i=1;i<n;i++){
				for(int j=i+1;j<=n;j++){
					if(solve({ts[i].a,ts[j].a})||solve({ts[i].a,ts[j].b})||
						solve({ts[i].b,ts[j].a})||solve({ts[i].b,ts[j].b})){f=1;break;}
				}
			}
		}
		if(f) cout<<"Yes!\n";
		else cout<<"No!\n";
	}
}

标签:直线,return,point,题解,线段,vec,端点,POJ3304,Segment
From: https://www.cnblogs.com/Sinktank/p/18304769

相关文章

  • [题解]UVA10902 Pick-up Sticks
    题意简述多测。给定坐标系上依次给定\(n\)根木棍的起始和终止坐标,按顺序放置这些木棍,询问最终处在最上层的木棍有哪些。\(n\le100000\)。保证任意时刻最上层的木棍不超过\(1000\)个。思路分析看起来数据范围很刁钻,不过除了暴力以外的方法想不出了,就写了一份上交,结果过了。思......
  • 题解:P10724 [GESP202406 七级] 区间乘积
    思路看到\(a_i\)很小,不难想到状压一类的东西。考虑把每个数的质因数当做二进制位,这个二进制位的\(1/0\)代表含有这个质因数的奇偶,再做一个异或前缀和,显然完全平方数的质因子个数一定为偶数,根据异或的性质,两个相同的数异或才为\(0\)所以只需要找到异或前缀和中相同的数的个......
  • 迷宫守卫 题解
    给个题目链接:迷宫守卫。下面直接开始讲了。发现一个事情,省选的题已经不怎么考板子难度很高的题了,现在考的都是思维难度非常高的题。首先,我们考虑字典序的性质,如果第一位劣,那么后面无论多优都没用,所以我们要优先满足靠前的位置。于是我们考虑使用二分来找出第一个数,后面以此类......
  • 题解:SP11469 SUBSET - Balanced Cow Subsets
    SP11469(折半搜索)题目大意:给出$N$个数,求可以被分成两个和相等的集合的子集数。思路分析:首先考虑朴素的DFS,每个数有三种情况:选为$A$集合,选为$B$集合,两个集合都不选。暴力DFS时间复杂度为$3^{20}$。观察到$N$很小,而$3^{10}$是可以通过本题的,于是考虑折半搜索。我......
  • P10720 [GESP202406 五级] 小杨的幸运数字 题解
    题意如果一个数的质因子中只有两个不同的数则输出\(1\),否则输出\(0\)。思路从第一个质因子遍历到\(sum\)的话很明显是\(O(nt)\)最大是\(n^{10}\)很明显会炸掉。所以遍历到\(sum\)是不行的,考虑正整数\(n\)最大的质因数是\(\sqrt{n}\)所以遍历到\(\sqrt{n}\)即......
  • 题解:SP10502 VIDEO - Video game combos
    大意构造一个长度为\(k\)(\(k\)是给定的)的串\(x\),使得对于\(∀1\leqi\leqn,s_i\)在\(x\)中的出现次数之和最大。输出这个最大值。思考考虑对\(s_i\)建AC自动机,然后dp。记\(dp[i][u]\)表示为长度为\(i\)的字符串,且当前已计算的节点是Trie上的编号为\(u......
  • 【题解】 [CSP-J 2021 T1] 分糖果
    题目描述题目大意给定正整数\(n\)、\(L\)、\(R\),求\(\max_{i\in\left[L,R\right]}{i\bmodn}\)。思路题目主要考察:分类讨论。众所周知,对于\(\forallx\),有$(x\bmodn)\in\left[0,n-1\right]$。可以分为两种情况讨论:如果\(\left\lfloor\frac{L......
  • 题解:CF1833F Ira and Flamenco
    思路因为要一个长度为\(m\)的,且最大与最小的元素之差小于等于\(m\)所以序列应为\(a_i,a_i+1,a_i+2\dots,a_i+m-1\),所以满足要求的序列之需要连续\(m\)个就行了,这个最开始排序,去重后用lower_bound求一下小于\(a_i+m-1\)的数有没有\(m\)个就行了。考虑满足要求序列的......
  • P8704 [蓝桥杯 2020 省 A1] 填空问题 题解
    题目传送门A.跑步训练我们经过仔细观察,可以发现每222分钟就会消耗300300......
  • P2754 [CTSC1999] 家园 / 星际转移问题题解
    开始时,将源点连一条权值为\(k\)的边到地球。然后以时间分层,从上一层的点连接到下一层的点,权值为飞船载人数量,并将代表月球的点连接到汇点。每加一层,在上一层的基础上进行增广,看能不能增加流量,如果流量变为\(k\),那么证明运送完成。可以证明枚举时间最多到\(1500\),图的点数不......