7-15 水果忍者 (30 分)
题目链接:https://pintia.cn/problem-sets/1108925599999025152/problems/1108925672111693828
题目大意:
现在假如你是“水果忍者”游戏的玩家,你要做的一件事情就是,将画面当中的水果一刀砍下。这个问题看上去有些复杂,让我们把问题简化一些。我们将游戏世界想象成一个二维的平面。游戏当中的每个水果被简化成一条一条的垂直于水平线的竖直线段。而一刀砍下我们也仅考虑成能否找到一条直线,使之可以穿过所有代表水果的线段。如果某条直线恰好穿过了线段的端点也表示它砍中了这个线段所表示的水果。假如你是这样一个功能的开发者,你要如何来找到一条穿过它们的直线呢?输出这条线段的两个端点的坐标。
具体思路::枚举每一条线段的下端点,从这个下端点向别的线段的上端点和下端点连线,然后判断一下(所有线段的上端点的最小斜率) 是不是大于 (所有线段的下端点的最小斜率),如果有合法的,那么所有线段的上端点的最小斜率对应的那个点和所有线段的下端点的最小斜率对应的点都是合法的,输出此时作为标准的点的下端点,另外一个点从两个合法的情况中找一个就可以了。
ps:假设当前枚举的是第i条线段,当我们枚举第i-1条线段的时候,形成的斜率可能会出现负数的情况。这个时候就相当于原来的上面的斜率变成了下面的斜率,下面的斜率变成了上面的斜率,注意坐标也要做相应的变化。
感谢qyn的讲解。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 # define inf 0x3f3f3f3f 5 const int maxn = 2e4+100; 6 struct node{ 7 int x; 8 int y1; 9 int y2; 10 }q[maxn]; 11 int main(){ 12 int n; 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++){ 15 scanf("%d %d %d",&q[i].x,&q[i].y1,&q[i].y2); 16 } 17 for(int i=1;i<=n;i++){ 18 double minn=inf,maxx=-inf; 19 int xup,yup; 20 //xup=yup=0; 21 int j; 22 for(j=1;j<=n;j++){ 23 if(j==i)continue; 24 int flag=1; 25 double up=(q[j].y1*1.0-q[i].y2*1.0)/(q[j].x*1.0-q[i].x*1.0); 26 double down=(q[j].y2*1.0-q[i].y2*1.0)/(q[j].x*1.0-q[i].x*1.0); 27 if(up<down)swap(up,down),flag=0; 28 if(down>minn||up<maxx)break; 29 maxx=max(maxx,down); 30 if(minn>up){ 31 minn=up; 32 xup=q[j].x; 33 yup=q[j].y1; 34 if(!flag){ 35 yup=q[j].y2; 36 } 37 } 38 } 39 if(j==n+1){ 40 printf("%d %d %d %d\n",q[i].x,q[i].y2,xup,yup); 41 break; 42 } 43 } 44 return 0; 45 }