A greedy algorithm follows heuristic of making the locally optimal choice at each stage with the intent of finding a global optimum.
思维框架:“每次找最……的物品……”
题目描述:
有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
题目描述:
有?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;
}
题目描述:
有n辆车大甩卖,第i辆车售价a[i]元。有m个人带着现金来申请购买,第i个到现场的人带的现金为b[i]元,只能买价格不超过其现金额的车子。你是大卖场总经理,希望将车和买家尽量多地进行一对一配对,请问最多卖出多少辆车?
怎样贪心呢?答案是“每次挑最昂贵的车,卖给最富有的人,若卖不出去,则便宜些”。
代码不开放……
题目描述:
有 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题