【CCCC】L3-012 水果忍者 (30分),枚举斜率

简介: 【CCCC】L3-012 水果忍者 (30分),枚举斜率

problem

L3-012 水果忍者 (30分)
2010年风靡全球的“水果忍者”游戏,想必大家肯定都玩过吧?(没玩过也没关系啦~)在游戏当中,画面里会随机地弹射出一系列的水果与炸弹,玩家尽可能砍掉所有的水果而避免砍中炸弹,就可以完成游戏规定的任务。如果玩家可以一刀砍下画面当中一连串的水果,则会有额外的奖励,如图1所示。

图 1

现在假如你是“水果忍者”游戏的玩家,你要做的一件事情就是,将画面当中的水果一刀砍下。这个问题看上去有些复杂,让我们把问题简化一些。我们将游戏世界想象成一个二维的平面。游戏当中的每个水果被简化成一条一条的垂直于水平线的竖直线段。而一刀砍下我们也仅考虑成能否找到一条直线,使之可以穿过所有代表水果的线段。

图 2

如图2所示,其中绿色的垂直线段表示的就是一个一个的水果;灰色的虚线即表示穿过所有线段的某一条直线。可以从上图当中看出,对于这样一组线段的排列,我们是可以找到一刀切开所有水果的方案的。

另外,我们约定,如果某条直线恰好穿过了线段的端点也表示它砍中了这个线段所表示的水果。假如你是这样一个功能的开发者,你要如何来找到一条穿过它们的直线呢?

输入格式:
输入在第一行给出一个正整数N(≤10
​4
​​ ),表示水果的个数。随后N行,每行给出三个整数x、y
​1
​​ 、y
​2
​​ ,其间以空格分隔,表示一条端点为(x,y
​1
​​ )和(x,y
​2
​​ )的水果,其中y
​1
​​ >y
​2
​​ 。注意:给出的水果输入集合一定存在一条可以将其全部穿过的直线,不需考虑不存在的情况。坐标为区间 [−10
​6
​​ ,10
​6
​​ ) 内的整数。

输出格式:
在一行中输出穿过所有线段的直线上具有整数坐标的任意两点p
​1
​​ (x
​1
​​ ,y
​1
​​ )和p
​2
​​ (x
​2
​​ ,y
​2
​​ ),格式为 x
​1
​​ y
​1
​​ x
​2
​​ y
​2
​​ 。注意:本题答案不唯一,由特殊裁判程序判定,但一定存在四个坐标全是整数的解。

输入样例:
5
-30 -52 -84
38 22 -49
-99 -22 -99
48 59 -18
-36 -50 -72
输出样例:
-99 -99 -30 -52

  • 给出n条垂直x轴的线段(端点坐标)
  • 试找到一条能贯穿所有线段的直线(任意两点)

solution

  • 尝试贪心,把最低的两个点连起来。但是都加了spj总感觉我过不了。贪心过了一个点hhh,
  • 是到计算几何题,看起来很像之前的凸包,可是不太会emm
  • 这题好像紫书上有做过的说,而且好像还是语法题emmm
  • 把所有线段按x从小到大排序,然后枚举所有的下端点。对于每次下端点,扫描其他所有线段,然后不断缩小斜率范围,确定一个斜率范围使他满足其他线段上的点,如果存在这样的斜率就输出。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10010;
struct seg{ double x, y1, y2; }s[maxn];
bool cmp(seg a, seg b){return a.x<b.x;}
double maxk,mink,ansmaxk,ansmink,ansx,ansy;
int main(){
    int n;  cin>>n;
    for(int i = 1; i <= n; i++)
        cin>>s[i].x>>s[i].y1>>s[i].y2;//y1在上,y2在下
    sort(s+1,s+n+1,cmp);
    for(int i = 1; i <= n; i++){
        ansmaxk = 1e9;
        ansmink = -1e9;
        int j;
        for(j = 1; j <= n; j++){
            if(j==i)continue;
            if(i<j){// j在i右侧
                maxk = (s[i].y2-s[j].y1)/(s[i].x-s[j].x);//
                mink = (s[i].y2-s[j].y2)/(s[i].x-s[j].x);
            }else{ //j在i左侧
                maxk = (s[i].y2-s[j].y2)/(s[i].x-s[j].x);
                mink = (s[i].y2-s[j].y1)/(s[i].x-s[j].x);
            }
            if(ansmaxk<mink || ansmink>maxk)break;
            if(maxk<ansmaxk){//不能满足限制条件的时候更新限制,即把ansk往下调
                ansmaxk = maxk;
                ansx = s[j].x;
                ansy = s[j].y1;
            }
            ansmink = max(ansmink, mink);
        }
        if(j==n+1){//存在解
            //线段i上取了最低点,则另一条线段要取最高点
            printf("%.0lf %.0lf %.0lf %.0lf\n",s[i].x,s[i].y2,ansx,ansy); 
            return 0;
        }
    }
    return 0;
}
目录
相关文章
|
9月前
【每日一题Day312】LC2240买钢笔和铅笔的方案数 | 完全背包 数学
【每日一题Day312】LC2240买钢笔和铅笔的方案数 | 完全背包 数学
73 0
|
9月前
【每日一题Day297】LC1444切披萨的方案数 | 动态规划+二维前缀和
【每日一题Day297】LC1444切披萨的方案数 | 动态规划+二维前缀和
83 0
|
8月前
|
C++
【洛谷 P2241】统计方形(数据加强版)题解(循环枚举)
该题目是1997年普及组的一道编程题,要求计算$n\times m$棋盘中的正方形和长方形数量(不计正方形)。输入包含两正整数$n,m\leq 5000$。输出为一行,两个正整数分别表示正方形和长方形数量。示例输入`2 3`,输出`8 10`。解题思路是将矩形数拆分为正方形数和长方形数,然后通过双重循环计算。AC代码使用C++编写,通过累加方法得出结果。
88 0
|
9月前
|
Go C++ 算法
C/C++每日一练(20230404) 旋转排序数组最小值、石头剪刀布、三数之和
C/C++每日一练(20230404) 旋转排序数组最小值、石头剪刀布、三数之和
67 0
C/C++每日一练(20230404) 旋转排序数组最小值、石头剪刀布、三数之和
|
9月前
【每日一题Day165】LC1039多边形三角剖分的最低得分 | 区间dp
【每日一题Day165】LC1039多边形三角剖分的最低得分 | 区间dp
66 0
|
算法
【算法挨揍日记】day12——153. 寻找旋转排序数组中的最小值、LCR 173. 点名
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
119 1
|
人工智能 BI
UPC-排课表+玉米田(容斥原理+组合数学公式)
UPC-排课表+玉米田(容斥原理+组合数学公式)
115 0
UPC-排课表+玉米田(容斥原理+组合数学公式)
【每日一题Day50】LC1812判断国际象棋棋盘中一个格子的颜色 | 找规律
【每日一题Day50】LC1812判断国际象棋棋盘中一个格子的颜色 | 找规律
91 0
PTA 7-1 打印三角形拼图 (15 分)
一个正方形可以用两个等边直角三角形拼出来。给定正方形的边长、两个三角形和对角线所用的符号,请你打印出这两个三角形拼出的正方形。
151 0
PTA 1084 外观数列 (20 分)
外观数列是指具有以下特点的整数序列
97 0

热门文章

最新文章