贪心就是遵循某种规则,不断贪心的选取当前最优策略的算法设计方法。本节通过几个经典贪心问题的展示来介绍贪心
贪心算法就是遵循某种规则,不断地选取当前最优策略
1.银币问题
const int V[6]={1,5,10,50,100,500};
int C[6];
int A;
void solve()
{
int ans=0;
for(int i=5;i>=0;i--)
{
int t=min(A/V[i],C[i]);
A-=t*V[i];
ans+=t;
}
printf("%d\n",ans);
}
2.区间问题
每次选择完成时间最短的
const int MAX_N=100000;
int N,S[MAX_N],T[MAX_N];
//用于对工作排序的pair数组
pair<int,int>itv[MAX_N];
void solve()
{
for(int i=0;i<N;i++)
{
itv[i].first=T[i];
itv[i].second=S[i];
}
sort(itv,itv+N);
int ans=0,t=0;
for(int i=0;i<N;i++)
{
if(t<itv[i].second)
{
ans++;
t=itv[i].first;
}
}
printf("%d\n",ans);
}
3.字典序最小问题
算法:
按照字典序比较S和将S反转后的字符串S'
如果S较小,就从S的开头取出一个文字
如果S’较小,就从S的末尾取出一个文字
int N;
char S[MAX_N+1];
void solve()
{
int a=0,b=N-1;
while(a<=b)
{
bool left=false;
for(int i=0;a+i<=b;i++)
{
if(S[a+i]<S[b-i])
{
left=true;
break;
}
else if(S[a+i]>S[b-i])
{
left=false;
break;
}
}
if(left)
putchar(S[a++]);
else
putchar(S[b--]);
}
putchar('\n');
}
4.其他例题
Saruman's Army
我们从最左边开始考虑。对于这个点,到距其R以内的区域内必须要有带标记的店,带有标记的这个点一定在此点右侧(包含这个点自身)
对于添加了符号的点右侧相距超过R的下一个点,采用同样的方法找到其右侧R距离以内最远的点添加标记
int N,R;
int X[MAX_N];
void solve(){
sort(X,X+N);
int i=0,ans=0;
while(i<N)
{
//s是没有被覆盖的最左的点的位置
int s=X[i++];
//一直向右前进直到距S的距离大于R的点
while(i<N&&X[i]<=s+R)
i++;
//p是新加上标记的点的位置
int p=X[i-1];
//一直向右前进直到距P的距离大于R
while(i<N&&X[i]<=p+R)
i++;
ans++;
}
printf("%d\n",ans);
}
2. Fence Repair
#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n))
{
long long ans=0;
int l;
priority_queue<int,vector<int>,greater<int> >q;
for(int i=0;i<n;i++)
{
scanf("%d",&l);
q.push(l);
}
while(!q.empty())
{
int a=q.top();
q.pop();
if(!q.empty())
{
int b=q.top();
q.pop();
int c=a+b;
// printf("%lld %d\n",ans,c);
ans+=c;
q.push(c);
}
}
printf("%lld\n",ans);
}
}