1.陶陶摘苹果luoguP1478
贪心
贪心假设:在所有可以摘到的苹果中,优先选择需要力气小的苹果。
贪心证明:因为要求的是共能摘多少个苹果,所以我们可以将每个苹果的价值都视为1。那么无论是摘比较费劲的苹果还是比较省力的苹果所得到的价值都是一样的。但如果摘比较省力的苹果,就可以留下更多的力气去摘其他的苹果。
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5100;
int n;
int s;
int a,b;
int y[N],idx=1;
int main(){
cin>>n>>s>>a>>b;
for (int i=1;i<=n;i++){
int high,force;
cin>>high>>force;
if (a+b>=high) y[idx++]=force;
}
sort(y+1,y+idx);
int ans=0;
for (int i=1;i<idx;i++){
s-=y[i];
if (s>=0)
ans++;
else
break;
}
cout<<ans<<endl;
return 0;
}
2. luoguP1610鸿山洞的灯
贪心
贪心假设:将所以灯按照坐标由小到大排序后,只要有符合条件的灯就将它关闭。
贪心证明:由于已经排完序,所以灯的坐标单调递增。设当前灯i可关闭,i+1也可以关闭,且如果关闭i,则i+1无法关闭,如果关闭i+1,则i无法关闭。那么由于i+1的坐标更靠后,i+1比i更容易满足让其它灯可以关闭的条件。且i与i+1的价值一样(都会使答案+1),所以i+1比i更优,所以应关闭第i盏灯。
#include<bits/stdc++.h>
using namespace std;
int n,dist,a[100002],sum;
int main()
{
cin>>n>>dist;
for(int i=1; i<=n; i++)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=2; i<=n-1; i++)
{
if(a[i+1]-a[i-1]<=dist)
{
a[i]=a[i-1];
sum++;
}
}
cout<<sum<<endl;
return 0;
}
3. luoguP1115最大字段和
前缀和思想+贪心
贪心假设:设sum为当前字段和,ans为当前最大子段和。每输入一个数,sum的值就加上这个数,如果这个数比ans大的话,就将ans更新为sum。判断过后,如果sum<0,则将sum重置为0。(意为重新开始选择一个区间)。
贪心证明:
因为对于每一个sum,我们都在判断其是否<0之前,判断了其是否可以更新ans,所以如果我们可以遍历到所以可行的方案,那么该贪心做法就是成立的。如果sum<0,sum无论是加一个正数还是一个负数,都会是加上的数的值变小,所以不利于ans变大。如果ans>=0那么ans加上一个数,最终得到的值一定会比,加上的数的原数大,更加利于ans变大。
Tip:由于<0的数加上任何数,都会使这个数变小,>0的数加上任何数,都会使这个数变大,所以0常常作为贪心问题中取舍的分界线。
#include <bits/stdc++.h>
using namespace std;
int n,ans,sum,now;
int main()
{
scanf("%d",&n);
scanf("%d",&now);
ans=now;
if(now>0) sum=now;
for(register int i=2;i<=n;i++)
{
scanf("%d",&now);
sum+=now;
if(sum>ans) ans=sum;
if(sum<0) sum=0;
}
printf("%d",ans);
return 0;
}