目录
一 题目
二 思路
这道题的答案是一定有的,也就是说一定会有一条线段穿过所有的线段。我们把这条直线成为L。那么,现在我们把L向上平移,直到到达极限的平移位置,这个位置的L一定穿过某条直线的端点,因此,答案L中的一个点是某条直线的上端点。然后,我们把这条直线L绕着这个点旋转,一定可以使得L经过另一条直线的上端点或者下断点,所以,答案L的另一个点是某条直线的上端点或者下端点。
于是,我们可以枚举每个上端点是直线中一个点的情况,与另外一个点的上、下端点组成最大、最小斜率,然后让这个点不断与其他点组成最大、最小斜率,不断缩小斜率的合法范围,如果与所有点的最大、最小斜率最后组合成功,那么就能找到答案。如果最后范围没有找到,说明这个点不适合做上端点,继续枚举下一个点。时间复杂度为o()。
三 代码
#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;
}