贪心算法(英语:greedy algorithm),是用计算机来模拟一个「贪心」的人做出决策的过程。这个人十分贪婪,每一步行动总是按某种指标选取最优的操作。而且他目光短浅,总是只看眼前,并不考虑以后可能造成的影响。
可想而知,并不是所有的时候贪心法都能获得最优解,所以一般使用贪心法的时候,都要确保自己能证明其正确性。贪心算法在有最优子结构的问题中尤为有效。最优子结构的意思是问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。(OI.Wiki)
排队接水
这是一道很典型的贪心题。
思路:结构体存储,自定义sort,累加即可。
活动安排问题
有开始结束时间,求最多可以参见几场活动。
思路:结构体存储,对结束时间进行排序。然后开始时间大于前一个结束时间即为可参加。
const int N = 1000021;
struct ka{
int st, ed;
}act[N];
void solve() {
int n; cin>>n;
for(int i = 0; i < n; ++i) {
cin>>act[i].st>>act[i].ed;
}
sort(act+0,act+n,[](ka a, ka b) {
return a.ed<b.ed;
});
int cnt = 0; int lastend = -1;
for(int i = 0; i < n; ++i) {
if(act[i].st >= lastend) {
cnt++;
lastend = act[i].ed;
}
}
cout<<cnt;
}
匀糖果问题
思路:先吃掉第一个多余的,之后第二个如果相加大于x,则吃掉 第一个+第二个-x,再令第二个为 x-第一个糖果数量。以此类推…
LL pre,sif;
LL x,n; cin>>n>>x;
cin>>pre;
LL ans = 0;
if(pre > x) ans += pre-x, pre = x;
n--;while(n--) {
cin>>sif;
if(pre + sif > x) {
ans += pre + sif - x;
sif = x - pre;
}
pre = sif;
}
cout<<ans;
铺路问题
思路:递推。dp[N], a[N]; dp[1] = a[1];
如果第i个数a[i] < a[i-1],那么在铺第i-1个的时候就可以顺带铺上,因此 dp[i] = dp[i-1];
如果第i个数a[i] > a[i-1],那么表示i-1的铺完还剩几个 – a[i] - a[i-1],那么就相当于重新开始 dp[i] = dp[i-1] + ( a[i] - a[i-1] )
int n; cin>>n;
rep(i,1,n) cin>>a[i];
int ans = 0;
dp[1] = a[1];
for(int i = 2; i <= n; ++i) {
if(a[i] > a[i-1]) {
dp[i] = dp[i-1] + (a[i] - a[i-1]);
} else dp[i] = dp[i-1];
}
cout<<dp[n];
覆盖问题
问题概述:用最少线段覆盖掉一个线段。
与活动安排问题相似,sort最大右端点;
活动安排问题: 最多 min结束时间入手
覆盖问题: 最少 max右端点入手