简单贪心算法 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} |a[i] - x| = |a[1] - x| + |a[2] - x| + \ldots + |a[n] - x| sum=i=1∑n∣a[i]−x∣=∣a[1]−x∣+∣a[2]−x∣+...+∣a[n]−x∣

的式子

  • 当 x 取得 n 个数的中位数时 , 和最小
  • 和最小为 : ( a [ n ] − a [ 1 ] ) + ( a [ n − 1 ] − a [ 2 ] ) + ... + ( a [ n + 1 − n / 2 ] − a [ n / 2 ] ) (a[n]−a[1])+(a[n−1]−a[2])+...+(a[n+1−n/2]−a[n/2]) (a[n]−a[1])+(a[n−1]−a[2])+...+(a[n+1−n/2]−a[n/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 ] sum[c,k] > sum[a,k] sum[c,k]>sum[a,k] -> s u m [ a , c ] < 0 sum[a,c]<0 sum[a,c]<0 -> 与贪心策略矛盾 -> 所以贪心策略正确

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

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

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


相关推荐
草莓熊Lotso21 分钟前
【Linux系统加餐】从原理到封装:基于建造者模式实现System V信号量工业级C++封装
android·linux·运维·服务器·网络·c++·建造者模式
爱睡懒觉的焦糖玛奇朵6 小时前
【从视频到数据集:焦糖玛奇朵的魔法工具使用说明】
人工智能·python·深度学习·学习·算法·yolo·音视频
Runawayliquor7 小时前
opbase:CANN 所有算子的公共地基
大数据·数据库·人工智能·算法
徐安安ye7 小时前
FlashAttention 为什么对序列长度这么“敏感”?
人工智能·算法
kyle~8 小时前
机器视觉---熔池相机(穿透强光的视觉感知)
c++·数码相机·计算机视觉·机器人·焊接机器人
宏笋8 小时前
C++ Coroutines(协程) 详解
c++
王老师青少年编程8 小时前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维前缀和】:求区间和
c++·前缀和·csp·高频考点·信奥赛·求和区间和
黎阳之光8 小时前
黎阳之光:以视频孪生重构智能监盘,为燃机打造新一代智慧电厂大脑
大数据·人工智能·算法·安全·数字孪生
绝知此事9 小时前
【算法突围 02】树形结构与数据库索引:树形结构与数据库索引:从 BST 到 B+ 树的演化与 MySQL 优化
数据库·mysql·算法·面试·b+树
kyle~9 小时前
机器人时间链路---工程流程示例
c++·3d·机器人·ros2