算法竞赛备赛——贪心

贪心

基本原理:每一步都选择局部最优解,而尽量不考虑对后续的影响,最终达到全局最优解。

局限性:贪心算法不能保证获得全局最优解,但在某些问题上具有高效性。

特征:贪心选择性质,最优子结构性质,(操作次数一定,不同操作产生贡献相同,每次选择代价最小的)贪心往往和排序、优先队列等一起出现。

经验:

  • 简单排序模型:当混乱的数据不好处理且排序不影响答案时,尝试先排序再分析。
  • 总操作数一定情况下 的最小代价模型,每次都选择代价最小的进行合并
  • 最少数目的贪心模型
  • 找规律的贪心

例题

最小化战斗力差距

蓝桥 知识点:贪心

问题描述

小蓝是机甲战队的队长,他手下共有 n名队员,每名队员都有一个战斗力值 wi。现在他需要将这 n名队友分成两组 a 和 b,分组必须满足以下条件:

  • 每个队友都属于 a组或 b 组。
  • a组和 b 组都不为空。
  • 战斗力差距最小。

战斗力差距的计算公式为 ∣max⁡(a)−min⁡(b)∣,其中 max⁡(a) 表示 a 组中战斗力最大的,min⁡(b)表示 b组中战斗力最小的。

请你计算出可以得到的最小战斗力差距。

输入格式

第一行一个整数 n,表示队员个数。

第二行 n 个整数 w1,w2,w3…wn,分别表示每名队友的战斗力值。

数据范围保证:2≤n≤10^5,1≤wi≤10^9。

输出格式

输出一个整数,表示可以得到的最小战斗力差距。

样例输入
3
1 2 3
样例输出
1
说明

样例中,当 a=[1,3],b=[2],此时战斗力差距为 1,无法得到比 1 更小的安排方式。

#include
using namespace std;
using ll=long long;
const int N=1e5+9;

int a[N];

int main(){
	int n; cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i];
	sort(a+1,a+n+1);
	int ans=a[2]-a[1];
	for(int i=3;i<=n;++i){
		ans=min(a[i]-a[i-1],ans);
	}
	cout<

谈判

蓝桥 知识点:贪心

题目描述

在很久很久以前,有 n个部落居住在平原上,依次编号为 1到 n。第 i个部落的人数为 ti。

有一年发生了灾荒。年轻的政治家小蓝想要说服所有部落一同应对灾荒,他能通过谈判来说服部落进行联合。

每次谈判,小蓝只能邀请两个部落参加,花费的金币数量为两个部落的人数之和,谈判的效果是两个部落联合成一个部落(人数为原来两个部落的人数之和)。

输入描述

输入的第一行包含一个整数 n,表示部落的数量。

第二行包含 n个正整数,依次表示每个部落的人数。

其中,1≤n≤1000,1≤ti≤10^4。

输出描述

输出一个整数,表示最小花费。

输入输出样例
示例 1

输入

4
9 1 3 5

输出

31
#include
using namespace std;
using ll=long long;
const int N=1e5+9;

priority_queue,greater> pq;	//注意优先队列的参数 默认降序排列!!!

int main(){
	int n; cin>>n;
	for(int i=1;i<=n;++i) {
		ll x; cin>>x;
		pq.push(x);
	}
	ll ans=0;
	while(pq.size()>=2){
		ll x=pq.top(); pq.pop();
		ll y=pq.top(); pq.pop();
		pq.push(x+y);
		ans+=x+y;
	}
	cout<

纪念品分组

蓝桥 知识点:贪心

题目描述

元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。

你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。

输入描述

第 1 行包括一个整数 w (80≤w≤200),为每组纪念品价格之和的上限。

第 2 行为一个整数 n (1≤n≤30000),表示购来的纪念品的总件数。

第3 ~ n+2行每行包含一个正整数 pi (5≤pi≤w),表示所对应纪念品的价格。

输出描述

输出一行,包含一个整数,即最少的分组数目。

输入输出样例
示例 1

输入

100
9
90
20
20
30
50
60
70
80
90

输出

6
#include
using namespace std;
using ll=long long;
const int N=1e5+9;

int a[N];

int main(){
	int m; cin>>m;
	int n; cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i];
	sort(a+1,a+1+n);					//先排序 
	int l=1,r=n,ans=0;
	while(l<=r){
		ans++;
		if(l==r) break;
		if(a[l]+a[r]<=m){	//只能装两个 看最大与最小能否装在一起
			l++;r--;
		}else{
			r--;
		}
	}
	cout<

分糖果

蓝桥 知识点:贪心

问题描述

最近暑期特训算法班的同学们表现出色,他们的老师肖恩决定给他们分发糖果。肖恩购买了 n 个不同种类的糖果,用小写的阿拉伯字母表示。每个糖果必须分发给一个同学,并且每个同学至少要分到一个糖果。同学们的开心程度定义为他们所分到的糖果组成的字符串 s[i]的字典序。肖恩希望同学们的开心程度相差尽量小,因此他要找到一种方案,使得所有糖果组成的字符串中字典序最大的字符串尽可能小。请输出能够实现字典序最小可能的 max⁡(s[1],s[2],s[3],…,s[x])。

输入描述

第一行输入两个整数 n 和 x ,分别表示有 n个糖果 x个同学。

第二行输入一个长度为 n的字符串 S , S[i]表示第 i个糖果的种类。

数据保证 1≤n≤10^6,1≤x≤n,S[i]∈[′a′,′z′] 。

输出描述

输出一个字符串,为所有糖果组成的字符串中字典序最大的字符串最小的可能值。

样例输入
6 2
caabdc

样例输出

abccd

说明

一个最优分配方案是一个同学拿到 abccd ,一个同学拿到 a 。

#include
using namespace std;
using ll=long long;
const int N=1e6+9;

char s[N];

int main(){
	int n,x; cin>>n>>x;
	cin>>s+1;
	sort(s+1,s+1+n);
	if(s[1]==s[n]){			//8 3 aaaaaaaa  aa aaa aaa->字典序最大的最小的可能情况
		for(int i=1;i<=ceil((double)n/x);++i) cout<字典序最大的最小的可能情况
		for(int i=x;i<=n;++i) cout<字典序最大的最小的可能情况
		cout<

你可能感兴趣的:(算法竞赛备赛,算法,数据结构,蓝桥杯)