简单贪心算法 cpp


8. 贪心

题目 两极分化

  1. 贪心算法

    1. 即贪心策略 : 用局部最优找出全局最优

      1. 把解决问题的过程分成若干步

      2. 每一步都用看起来最优的解法

      3. 以此希望 局部最优 -> 全局最优

  2. 贪心算法的特点

    1. 贪心 -> 贪婪 + 鼠目寸光 -> 有可能出现错误 -> 需要证明策略正确 (反证/数学归纳/交换论证/...)

    2. 问题不同 , 贪心策略不同 -> 没有固定模板

  3. 学贪心的方法

    1. 认知 : 遇到新的贪心题 若不会 很正常

    2. 前期学习 , 重在学习策略 , 把策略当经验吸收

    3. 练习时 , 尽可能证明策略的正确性


8.1 简单贪心

8.1.1 货仓地址

!洛谷

P10452 货仓选址

P10452 货仓选址 - 洛谷

题目描述

在一条数轴上有 N N N 家商店,它们的坐标分别为 A 1 ∼ A N A_1 \sim A_N A1∼AN。

现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。

为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。

输入格式

第一行输入整数 N N N。

第二行 N N N 个整数 A 1 ∼ A N A_1 \sim A_N A1∼AN。

输出格式

输出一个整数,表示距离之和的最小值。

输入输出样例 #1

输入 #1

复制代码
4
6 2 9 1

输出 #1

复制代码
12

说明/提示

数据保证, 1 ≤ N ≤ 10 5 1 \le N \le 10^5 1≤N≤105, 0 ≤ A i ≤ 40000 0 \le A_i \le 40000 0≤Ai≤40000。

思路:

结论 : 建立在中位数的地方 (n为奇 -> 中位数 , n 为偶 -> 两个中位数都可以), 距离之和最小

注意要排序

代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;
typedef long long LL;

LL n;
LL a[N], sum;

int main()
{
	cin >> n;
	
	for(int i = 1; i <= n; i++ ) cin >>  a[i];

	sort(a + 1, a + 1 + n);

	for(int i = 1; i <= n; i++) sum += abs(a[n/2] - a[i]);	
		
	cout << sum;	

	return 0;
 } 
证明:

绝对值不等式 : ∣ a − x ∣ + ∣ b − x ∣ ≥ ∣ a − b ∣ |a-x|+|b-x| ≥ |a-b| ∣a−x∣+∣b−x∣≥∣a−b∣

性质 : 当 x 在 ( a , b ) (a,b) (a,b) 之间时, 取等号 , 并取最小值

结论 :

形如
sum = ∑ i = 1 n ∣ a i − x ∣ = ∣ a 1 − x ∣ + ∣ a 2 − x ∣ + ... + ∣ a n − x ∣ \text{sum} = \sum_{i=1}^{n} |ai - x| = |a1 - x| + |a2 - x| + \ldots + |an - x| sum=i=1∑n∣ai−x∣=∣a1−x∣+∣a2−x∣+...+∣an−x∣

的式子

  • 当 x 取得 n 个数的中位数时 , 和最小
  • 和最小为 : ( a n − a 1 ) + ( a n − 1 − a 2 ) + ... + ( a n + 1 − n / 2 − a n / 2 ) (an−a1)+(an−1−a2)+...+(an+1−n/2−an/2) (an−a1)+(an−1−a2)+...+(an+1−n/2−an/2)

先大胆猜想策略 , 然后验证


8.1.2 最大子段和

!洛谷

P1115 最大子段和

P1115 最大子段和 - 洛谷

题目描述

给出一个长度为 n n n 的序列 a a a,选出其中连续且非空的一段使得这段和最大。

输入格式

第一行是一个整数,表示序列的长度 n n n。

第二行有 n n n 个整数,第 i i i 个整数表示序列的第 i i i 个数字 a i a_i ai。

输出格式

输出一行一个整数表示答案。

输入输出样例 #1

输入 #1

复制代码
7
2 -4 3 -1 2 -4 3

输出 #1

复制代码
4

说明/提示

样例 1 解释

选取 3 , 5 3, 5 3,5 子段 { 3 , − 1 , 2 } \{3, -1, 2\} {3,−1,2},其和为 4 4 4。

数据规模与约定
  • 对于 40 % 40\% 40% 的数据,保证 n ≤ 2 × 10 3 n \leq 2 \times 10^3 n≤2×103。
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 2 × 10 5 1 \leq n \leq 2 \times 10^5 1≤n≤2×105, − 10 4 ≤ a i ≤ 10 4 -10^4 \leq a_i \leq 10^4 −104≤ai≤104。

2026/01/21:增加一组 hack 数据

思路:

贪心策略 :

  • 从第一个元素起 累加

  • sum >= 0 : 继续累加

  • sum < 0 : 舍去这一段 , 从下一个位置开始重新累加

代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

int main()
{
	int n;
	cin >> n;
	
	LL sum = 0 , a , ret = -1e6;
	
	while(n--)
	{
		cin >> a;
		sum += a;
		ret = max(ret , sum);
		if(sum < 0) sum = 0;
	}
	
	cout << ret << endl;
	
	return 0;
}
证明:

------±-----±----±-----±----±---

----- a---- c --- k1 -- b -- k2

  • 从 ( a , b ) (a,b) (a,b) 之间任何一个点开始 , 都不可能是最优解

  • 反证法 :

    1. 从c点开始 , 向后累加时 , 在 ( a , b ) (a,b) (a,b) 之间拿到更优解

      s u m c , k > s u m a , k sumc,k > suma,k sumc,k>suma,k -> s u m a , c < 0 suma,c<0 suma,c<0 -> 与贪心策略矛盾 -> 所以贪心策略正确

    2. 从c点开始 , 向后累加时 , 越过b点 , 拿到最优解

      s u m c , b > s u m a , b sumc,b > suma,b sumc,b>suma,b -> s u m a , c < 0 suma,c < 0 suma,c<0 -> 与贪心策略矛盾 -> 所以贪心策略正确

看着思路离谱 , 在贪心算法中 , 很正常 , 重要的是证明


相关推荐
Irissgwe4 分钟前
算法的时间复杂度和空间复杂度
数据结构·c++·算法·c·时间复杂度·空间复杂度
随意起个昵称5 分钟前
区间dp-基础题目3(永别)
c++·算法
周末也要写八哥11 分钟前
有向图Hierholzer算法的另一种实现
算法
bIo7lyA8v14 分钟前
算法调优中的性能回归与基准测试分析的技术8
算法·数据挖掘·回归
有点。16 分钟前
C++贪心算法二(练习题)
c++·算法·贪心算法
西安邮电大学20 分钟前
贪心算法详细讲解
java·后端·其他·算法·面试
开源Z20 分钟前
LeetCode 135 · 分发糖果:两次扫描,先左后右取最大
算法·leetcode
坚果派·白晓明26 分钟前
鸿蒙 PC 应用集成 libhv 鸿蒙化三方库 —— AtomCode + Skills 驱动的高效集成实践
c语言·c++·ai编程·harmonyos·atomcode
触底反弹42 分钟前
拷个 .exe 到新电脑就跑不起来?你缺的不是文件,是对链接的理解
c++·windows·操作系统
装不满的克莱因瓶1 小时前
掌握生成对抗网络(GAN)的优化目标与评估指标——从博弈函数到生成质量衡量体系
人工智能·python·深度学习·算法·机器学习