Peter算法小课堂—贪心算法

A greedy algorithm follows heuristic of making the locally optimal choice at each stage with the intent of finding a global optimum.

思维框架:“每次找最……的物品……”

太戈编程2637题

题目描述:

有n个正整数,现在进行若干次操作:每次删去2个数a和b,然后加入1个数a*b+1。反复操作直到只有一个数,求最小剩下几?

怎样贪心呢?就只有两种可能,①每次挑最小的数合并 ②每次挑最大的数合并。假设有三个数a,b,c,且a<b<c。按①,第一次ab+1和c,第二次(ab+1)*c+1=abc+c+1。按②,第一次bc+1,第二次(bc+1)*a+1=abc+a+1显然小于①,因此采取②方案。即每次挑最大的数合并。注意:数组不能变换长度,得使用multiset(当然,用vector也行)。

代码:

#include <bits/stdc++.h>
using namespace std;
int n;
int main(){
	cin>>n;
	multiset<int> s;
	multiset<int>::iterator it;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		s.insert(x);
	}
	for(int i=1;i<=n-1;i++){
		it=s.end();
		it--;
		int a=*it;
		s.erase(it);
		it=s.end();
		it--;
		int b=*it;
		s.erase(it);
		s.insert(a*b+1);
	}
	cout<<*s.begin()<<endl;
	return 0;
}

练习1:太戈编程113

太戈编程1744题

题目描述:

有 n 个人要过河,第i人重w[i]。每艘小船只有2个位置,最大载重为c。求最少要几艘船?

如何贪心呢?答案是“每次挑最轻的人,搭配另1人尽量重,若无人搭配则独自开船”

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,c,w[100009];
int main(){
	cin>>n>>c;
	for(ll i=1;i<=n;i++) cin>>w[i];
	sort(w+1,w+1+n);
	ll ans=0;
	ll i=1;j=n;
	while(i<j){
		ans++;
		if(w[i]+w[j]<=c) i++,j--;
		else j--;
	}
	if(i==j) ans++;
	cout<<ans<<endl;
	return 0;
}

太戈编程655题

题目描述:

有n辆车大甩卖,第i辆车售价a[i]元。有m个人带着现金来申请购买,第i个到现场的人带的现金为b[i]元,只能买价格不超过其现金额的车子。你是大卖场总经理,希望将车和买家尽量多地进行一对一配对,请问最多卖出多少辆车?

怎样贪心呢?答案是“每次挑最昂贵的车,卖给最富有的人,若卖不出去,则便宜些”。

代码不开放……

太戈编程694题

题目描述:

有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张。可以在任一堆上取若干张纸牌,然后移动。 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。 现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。输出最少的移动次数,若无解输出-1。

给大家一个概念:集合类问题和序列类问题。集合类问题指不管你怎样调动数据顺序,都不影响结果。序列类问题指不仅要考虑数据的大小,还要考虑数据移动的方向。此题就属于序列类问题。

如何贪心呢?有童鞋会想将纸牌最多的那一堆拆分。比如9 8 17 6,平均数为10,我们就将第三堆分给第一堆1张,给第二堆2张,给第四堆4张,共3次。但考虑一下1 1 17 9 26 6,平均数为10,有两个大于平均数的数,很麻烦。那应该怎样移动呢?

先看1,与平均数差9,从后面往前补9,变成10

再看10和-8,和为2,与2*10差18,从后面往前补18,变成10

再看10和10和-1,何为19,与3*10差11,从后面往前补11,变成10

我们就以这种思路进行下去就是最优解。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=109;
int n,ans,s[N],a[N];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
	itn avg=s[n]/n;
	for(int i=1;i<=n-1;i++){
		if(s[i]!=avg*i) ans++;
	}
	cout<<ans<<endl;
	return 0;
}

练习2:太戈编程693题

  • 29
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值