天梯赛 L3-012 水果忍者 思维+枚举+计算几何+排序

目录

一 题目

二 思路

三 代码


一 题目

二 思路

这道题的答案是一定有的,也就是说一定会有一条线段穿过所有的线段。我们把这条直线成为L。那么,现在我们把L向上平移,直到到达极限的平移位置,这个位置的L一定穿过某条直线的端点,因此,答案L中的一个点是某条直线的上端点。然后,我们把这条直线L绕着这个点旋转,一定可以使得L经过另一条直线的上端点或者下断点,所以,答案L的另一个点是某条直线的上端点或者下端点

于是,我们可以枚举每个上端点是直线中一个点的情况,与另外一个点的上、下端点组成最大、最小斜率,然后让这个点不断与其他点组成最大、最小斜率,不断缩小斜率的合法范围,如果与所有点的最大、最小斜率最后组合成功,那么就能找到答案。如果最后范围没有找到,说明这个点不适合做上端点,继续枚举下一个点。时间复杂度为o(n^2)

三 代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010,INF=0x3f3f3f3f;
struct node 
{
	int x,y1,y2;
}arr[N];
bool cmp(node x,node y){return x.x<y.x;}
int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++)cin>>arr[i].x>>arr[i].y1>>arr[i].y2;
	sort(arr+1,arr+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		bool flag=true;
		double kmax=INF,kmin=-INF;//初始化斜率正负无穷 
		double tmax,tmin;//要求的两点之间的斜率最大值和最小值 
		int x,y;//确定第二个端点的坐标 
		for(int j=1;j<=n;j++)
		{
			if(i==j)continue;
			if(i<j)
			{
				tmax=(double)(arr[j].y1-arr[i].y1)/(arr[j].x-arr[i].x);
				tmin=(double)(arr[j].y2-arr[i].y1)/(arr[j].x-arr[i].x);
			}
			else
			{
				tmax=(double)(arr[i].y1-arr[j].y2)/(arr[i].x-arr[j].x);//最大斜率 
				tmin=(double)(arr[i].y1-arr[j].y1)/(arr[i].x-arr[j].x);//最小斜率 
			}
			//端点选哪个无所谓,第二个端点选上还是下无所谓,扩大或者缩小就顺便修改一下 
			if(kmax>tmax)kmax=tmax,x=arr[j].x,y=arr[j].y1;	
			if(kmin<tmin)kmin=tmin,x=arr[j].x,y=arr[j].y2;
			if( kmax<kmin )//说明这个点做上端点了,换一个点 
			{
				flag=false;
				break; 
			}
		}
		if(flag)
		{
			cout<<arr[i].x<<' '<<arr[i].y1<<' '<<x<<' '<<y<<'\n';
			break;	
		} 
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值