Algorithm-Pattern
  • Introduction
  • C & C++
    • C语言
      • C/C++编译器
      • 宏的使用
      • 编译过程
      • 指针 & 数组
      • 柔性数组
      • 函数指针 & 回调函数
      • C标准库之stdio
      • C标准库之string
      • C标准库之errno
      • C标准库之stdarg
      • C标准库之regex
    • C++基础语法
      • 自增(++) & 自减(--)
      • c语言到c++
      • 可变模板参数
      • 强制类型转换
      • C/C++类型转换的本质
      • 指针 & 引用
      • const的用法
      • static的用法
      • 重要的关键字(一)
      • 重要的关键字(二)
      • 内存申请和释放
      • 内联函数
      • 函数 & 运算符重载
      • 面向对象之封装
      • 构造函数 & 析构函数
      • 面向对象之继承
      • 面向对象之多态
      • 泛型编程
      • 异常
      • 再谈函数指针
    • C++并发编程
      • C++的锁
      • 并发与多线程
    • C++高级特性
      • 函数对象
      • 移动语义 & 完美转发
      • lambda表达式
      • RTTI技术
      • RAII技术
      • 智能指针
      • 模板的特化
      • C++静态库和动态库
      • 内存溢出和内存泄漏
    • STL基础
      • String
      • array/vector/list
      • deque/priority_queue
      • set/map
      • unordered_set/unordered_map
      • algorithm_1
      • functional
      • allocator
    • C++标准库
      • IO
      • Tuple
      • regex
      • bitset
      • numeric
    • STL深入源码
      • vector内部实现
      • deque内部实现
      • sort函数实现
    • 第三方库
      • JsonCpp
      • ProtoBuf
  • 数据结构
    • 线性表
    • 字符串
    • 栈和队列
    • 二叉树
    • 平衡二叉树
    • 平衡多路搜索树
    • 树结构的延申
    • 图
    • 二进制
    • 散列表
  • 算法基础
    • 排序算法
    • 查找算法
    • 数学问题
    • 并查集
    • 递归算法
    • 附加——主定理
    • Catalan数
  • 算法设计思想
    • 滑动窗口思想
    • BFS/DFS
    • 二分法
    • 回溯法
    • 贪心算法
    • 分治法
    • 动态规划
    • 分支限界算法
    • 有限状态机(FSM)
  • LeetCode系列
    • 死磕二叉树
    • 股票买卖问题
    • 打家劫舍问题
    • 跳跃游戏问题
    • 括号匹配问题
    • 石子游戏问题
    • 子序列问题
    • 数组 & 矩阵
    • 排列 & 组合
  • 经典算法问题
    • 几何问题
    • 区间问题
    • 背包问题
    • 石子堆问题
    • 表达式求值
  • 面试题
    • 数据结构和算法基础
    • 程序设计题
      • 实现双线程交替打印
      • C++实现读写锁
      • 实现阻塞队列
      • 实现环形队列
      • 实现线程池
      • 实现智能指针
      • 实现string类
      • 实现高性能local cache
      • 实现内存池
      • 生产者-消费者模型
      • 设计定时器
    • 经典的算法题
    • C++面试题总结
    • 面试算法题总结
由 GitBook 提供支持
在本页
  • 1、利用几何性质解决问题
  • 吃葡萄
  • 2、解决几何问题
  • Max Points on a Line
  • Largest Rectangle in Histogram
  • Maximal Rectangle

这有帮助吗?

  1. 经典算法问题

几何问题

上一页排列 & 组合下一页区间问题

最后更新于4年前

这有帮助吗?

1、利用几何性质解决问题

有三种葡萄,每种分别有a、b、c颗。有三个人,第一个人只吃第1、2种葡萄,第二个人只吃第2、3种葡萄,第三个人只吃第1、3种葡萄。适当安排三个人使得吃完所有的葡萄,并且且三个人中吃的最多的那个人吃得尽量少。

输入描述:

  • 第一行数字 T\mathit TT ,表示数据组数。

  • 接下来 T\mathit TT 行,每行三个数 a,b,c\mathit a,b,ca,b,c

  • 1≤a,b,c≤1018,1≤T≤101 \leq a,b,c \leq 10^{18} , 1 \leq T \leq 101≤a,b,c≤1018,1≤T≤10

输出描述:

对于每组数据,输出一行一个数字表示三个人中吃的最多的那个人吃的数量。

先不管每个人只能吃两种特定葡萄的约束,你怎么让「吃得最多的那个人吃得最少」?显然,只要平均分就行了,每个人吃(a+b+c)/3颗葡萄。即便不能整除,比如说a+b+c=8,那也要尽可能平均分,就是说一个人吃 2 颗,另两个人吃 3 颗。

综上,「吃得最多的那个人吃得最少」就是让我们尽可能地平均分配,而吃的最多的那个人吃掉的葡萄颗数就是(a+b+c)/3向上取整的结果,也就是(a+b+c+2)/3。

PS:向上取整是一个常用的算法技巧。大部分编程语言中,如果你想计算M除以N,M / N会向下取整,你想向上取整的话,可以改成(M+(N-1)) / N。

现在考虑一下如果加上「每个人只能吃特定两种葡萄」的限制,怎么做?也就是说,每个人只能吃特定两种葡萄,你也要尽可能给三个人平均分配,这样才能使得吃得最多的那个人吃得最少。

这可复杂了,如果用X, Y, Z表示这三个人,就会发现他们组成一个三角关系:

如果把葡萄的颗数a, b, c作为三条线段,它们的大小作为线段的长度,想一想它们可能组成什么几何图形?我们的目的是否可以转化成「尽可能平分这个几何图形的周长」?

三条线段组成的图形,那不就是三角形嘛?不急,我们小学就学过,三角形是要满足两边之和大于第三边的,假设a < b < c,那么有下面两种情况:

如果a + b > c,那么可以构成一个三角形,只要取每条边的中点,就一定可以把这个三角形的周长平分成三份,且每一份都包含两条边:

也就是说,这种情况下,三个人依然是可以平均分配所有葡萄的,吃的最多的人最少可以吃到的葡萄颗数依然是(a+b+c+2)/3。

如果a + b <= c,这三条边就不能组成一个封闭的图形了,那么我们可以将最长边c「折断」,也就是形成一个四边形。

这里面有两种情况:

对于情况一,a + b和c的差距还不大的时候,可以看到依然能够让三个人平分这个四边形,那么吃的最多的人最少可以吃到的葡萄颗数依然是(a+b+c+2)/3。

随着c的不断增大,就会出现情况二,此时c > 2*(a+b),由于每个人口味的限制,X顶多吃完a和b,为了尽可能平分,c边需要被Y或Z平分,也就是说此时吃的最多的人最少可以吃到的葡萄颗数就是(c+1)/2,即平分c边向上取整。

int main()
{
    int T = 0;
    long long a = 0, b = 0, c = 0;
    cin >> T;
    while(T > 0){
        cin >> a >> b >> c;
        long long temp = 0;
        if(a>b) temp = a, a = b, b = temp;
        if(b>c) temp = b, b = c, c = temp;
        if(a>b) temp = a, a = b, b = temp;
        if(c > 2 * (a + b)){
            cout << (c + 1) / 2 << endl;
        }else{
            cout << (a + b + c + 2) / 3 << endl;
        }
        --T;
    }
    return 0;
}

给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。

2、解决几何问题

✏️
Max Points on a Line
Largest Rectangle in Histogram
Maximal Rectangle
✏️
吃葡萄