目录
算法简介:
其实就是先从答案出发,再判断可不可行。当然,如果『』有单调性的话,还可以二分。
至于这个『』是什么,请听后文分析。
注:本文章主要将思路,以及解题过程,模板题会穿插代码,剩下的只会给思路
题目
0. 臭皮匠
题目描述
个臭皮匠坐成⼀排,从左数第
个人智商为
他们将分组挑战诸葛亮。每⼀组只可以安排相就坐的若干个臭皮匠上场挑战,必须保证每组的总智商不低于
,求最多派出几组臭皮匠?
解答
注:不用看,我没有打错标题,这题只是一个引入。先把给文章的主题(二分答案)抛却脑后。
首先,看到这种题,想到的就是……
没错,我们伟大的切钢条问题。
状态: 前
个人最多能派出几组
决策:上一组的最后位置
转移方程:
这个时候,我们发现:
-
本身单调不降
- 求和符号(约束条件)是单调降
所以,递推式变成了这样得:
变成了贪心。
代码自然长这样:
int cnt = 0, sum = 0;
for (int i = 0; i < n; i ++) {
sum += x [i];
if (sum > = m) {
sum = 0;
cnt ++;
}
}
cout << cnt;
1. 臭皮匠加强版
题目描述
个臭皮匠坐成⼀排,从左数第
个人智商为
他们将分组挑战诸葛亮。每⼀组只可以安排相就坐的若干个臭皮匠上场挑战,必须安排
组,求诸葛亮得智商最大可以为多少?
解答
思路:转化为已知问题
不知道诸葛亮得智商🤔 |
简单粗暴:不知道就枚举 |
于是我们从大到小枚举诸葛亮得智商。
然后,用上一题的贪心法进行判断:诸葛亮的智商是否能派出 组
复杂度:
优化:可行性的单调性
我们知道: = 如果诸葛亮智商为
是否能派出
组。
显然:如果,则
所以, 函数有可行性的单调性,再
和
之间有一个分割点
即:
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
所以,我们可以用二分法对 进行枚举,称为二分答案。
复杂度:
#include <bits/stdc++.h>
using namespace std;
int n, k, x [10000];
bool OK (int tmp) {
int cnt = 0, sum = 0;
for (int i = 0; i < n; i ++) {
sum += x [i];
if (sum > = tmp) {
sum = 0;
cnt ++;
}
}
if (cnt >= k) return true;
else return false;
}
int main () {
cin >> n >> k;
int sum = 0;
for (int i = 0; i < n; i ++) {
cin >> x [i];
sum += x [i];
}
sum /= k;
int left = 0, right = sum;
while (left < right) {
int mid = (left + right + 1) / 2;
if (OK (mid)) left = mid;
else right = mid - 1;
}
cout << left;
}
好了,这道题就这样了。
1.5. 一点点的小结:
首先,我们知道了『』代表了 可行性
其次……
2. 跳石头
题目描述:
⼀条笔直的河道中分布着⼀些岩石。已选好两块岩石作为起点和终点,间距为 。起点和终点之间
块岩石。选手们将从起点出发,每步跳向相邻的岩石,直至终点。为了提高比赛难度组委会计划移走
块岩石,使选手们在比赛过程中的最短跳跃距离尽可能长
解答:
- 难点:优化目标是⼀个全局量(最小值的最大值)
那这样的优点是什么呢:我们把集体约束拆成了单个的约束
这种题就是套路,只需要枚举这个 就可以了,再进行判断。
那么,我们要写的 函数的定义就是:使得相邻间隔全部都
可不可行。
仔细看一眼👁️,这道题 其实就是上一道题……
函数给一下:
bool OK (int v) {
int cnt = 0, lst = 0;
for (int i = 0; i <= n + 1; i ++) {
if (x [i] - x [lst] < v) cnt ++;
else lst = i;
}
return cnt <= m;
}
3. 人工智能开关
题目描述:
个灯泡排一直线,开始时有某些灯开着。每次操作能且只能让恰好连续的
个灯泡进行一次开关(开着的灯会关掉,关着的灯会打开)。一旦
设定好就不能改变。求
为多少,可用最少的操作次数使灯全部关闭。如有多个
使次数相同,则输出最小的
。如无解输出
。
输入样例:
1101011
输出样例 :
3
解答:
首先,如果我们不知道 ,根本做不了这道题。
不知道 |
简单粗暴:不知道就枚举 |
那么 函数怎么写:
- 显然,同一段至多操作一次
- 每次找到最靠左的开着的灯
,操作
次(别无选择)
- 最后
盏灯决定了可行性
然后,很多读者开始帅气地写起了二分答案……
BUT, 这题的可行性没有单调性。
所以,这告诉我们,不能盲目地写二分,先判断单调性。
4. 送礼物就要体面
题目描述:
送礼讲究“体面”,所以很多礼品包装都非常漂亮。而你的送礼哲学是“体面”体现在“体积”。从 个礼品里你需要挑选
个,第
件的体积是
,价格是
。请问对于选出的
件礼品,总体积除以总价格最大是多少?保留两位小数。
输入样例:
3 2
2 2
3 5
1 2
输出样例:
0.75
解答:
首先,我们要了解一个场景:最优性价比场景
- 错误❌的贪心法
- 计算每件礼品的性价比:
- 按照单件性价比排序
- 选性价比最高的
件
原因:体积大的会拖累小的。
那应该选怎样的物品呢,仔细看:
那么,我们要选择的,就是最大的数
所以,判断依旧是 的复杂度。
然后,再枚举答案,最终复杂度:
5. 差距中位数
题目描述:
输入 个数
,求两两之差的中位数。
输入样例:
4
1 2 4 7
输出样例:
3
解答:
首先,我们分析得到:
共有 个差值,其中第
的值
这种题叫做 k优化问题
设 代表差值
的有几对
则
又∵ 单调不降,所以很明显,可以二分。
那么, 怎么写呢?
如果暴力枚举肯定超时:
我们发现如果排序,不会对结果产生影响
所以,我们排序之后去绝对值得
问题转化为:已知 ,求不超过
的最大的
这里, 也可以二分
最终复杂度:
当然,也可以优化到
最后的总结
结束:
好了,以上就是本期文章的全部内容了,也感谢你能读到这里。最后,求赞求收藏求评论求转发,最重要的是点一个大大的关注。你们的支持就是我写文章的最大动力,我们下期再见!