题目:
2010年风靡全球的“水果忍者”游戏,想必大家肯定都玩过吧?(没玩过也没关系啦~)在游戏当中,画面里会随机地弹射出一系列的水果与炸弹,玩家尽可能砍掉所有的水果而避免砍中炸弹,就可以完成游戏规定的任务。如果玩家可以一刀砍下画面当中一连串的水果,则会有额外的奖励,如图1所示。
图 1
现在假如你是“水果忍者”游戏的玩家,你要做的一件事情就是,将画面当中的水果一刀砍下。这个问题看上去有些复杂,让我们把问题简化一些。我们将游戏世界想象成一个二维的平面。游戏当中的每个水果被简化成一条一条的垂直于水平线的竖直线段。而一刀砍下我们也仅考虑成能否找到一条直线,使之可以穿过所有代表水果的线段。
图 2
如图2所示,其中绿色的垂直线段表示的就是一个一个的水果;灰色的虚线即表示穿过所有线段的某一条直线。可以从上图当中看出,对于这样一组线段的排列,我们是可以找到一刀切开所有水果的方案的。
另外,我们约定,如果某条直线恰好穿过了线段的端点也表示它砍中了这个线段所表示的水果。假如你是这样一个功能的开发者,你要如何来找到一条穿过它们的直线呢?
输入格式:
输入在第一行给出一个正整数 N ( ≤ 1 0 4 ) N(≤10^4) N(≤104),表示水果的个数。随后N行,每行给出三个整数 x 、 y 1 、 y 2 x、y_1、y_2 x、y1、y2,其间以空格分隔,表示一条端点为 ( x , y 1 ) (x,y_1) (x,y1)和 ( x , y 2 ) (x,y_2) (x,y2)的水果,其中 y 1 > y 2 y_1>y_2 y1>y2。注意:给出的水果输入集合一定存在一条可以将其全部穿过的直线,不需考虑不存在的情况。坐标为区间 [ − 1 0 6 , 1 0 6 ) [−10^6 ,10^6 ) [−106,106) 内的整数。
输出格式:
在一行中输出穿过所有线段的直线上具有整数坐标的任意两点 p 1 ( x 1 , y 1 ) p_1(x_1,y_1) p1(x1,y1)和 p 2 ( x 2 , y 2 ) p_2(x_2,y_2 ) p2(x2,y2),格式为 x 1 y 1 x 2 y 2 x_1 y_1 x_2 y_2 x1y1x2y2。注意:本题答案不唯一,由特殊裁判程序判定,但一定存在四个坐标全是整数的解。
输入样例:
5
-30 -52 -84
38 22 -49
-99 -22 -99
48 59 -18
-36 -50 -72
输出样例:
-99 -99 -30 -52
思路:
以每一条线段的最下面的端点去找斜率的范围,如果找到一个斜率可以切断所有线段则输出并返回。
代码:
#include<bits/stdc++.h>
using namespace std;
//使用double方便计算斜率
struct node{double x;double maxy;double miny;
}s[10005];
//所有线段从左向右排
bool cmp(node a,node b){return a.x<=b.x;
}
const double inf=999999999;
int ansid;
int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>s[i].x>>s[i].maxy>>s[i].miny;}sort(s+1,s+1+n,cmp);for(int i=1;i<=n;i++){
// 最大最小斜率 double ansmaxk=inf;double ansmink=-inf;double maxk,mink;int j;for(j=1;j<=n;j++){if(i==j){continue;}
// j在i左边 if(j>i){maxk=(s[j].maxy-s[i].miny)/(s[j].x-s[i].x);mink=(s[j].miny-s[i].miny)/(s[j].x-s[i].x);}
// j在i右边 else{maxk=(s[i].miny-s[j].miny)/(s[i].x-s[j].x);mink=(s[i].miny-s[j].maxy)/(s[i].x-s[j].x);}
// 超出范围 if(mink>ansmaxk||maxk<ansmink){break;}
// 更新斜率,使用最大的方便输出 if(maxk<ansmaxk){ansmaxk=maxk;
// 记录答案在那个线段 ansid=j;}ansmink=max(mink,ansmink);}
// 所有线段都在范围内 if(j==n+1){printf("%.0lf %.0lf %.0lf %.0lf",s[i].x,s[i].miny,s[ansid].x,s[ansid].maxy);return 0;} }return 0;
}