也是来到了速通c语言的第四天,坚持了几乎1/7啦,相信30天后肯定会整个人都不一样起来。
今天我们来介绍一下贪心算法!
#之前高中学习的时候还记得我们竞赛老师说过,只要学会了贪心(那种真正掌握了),其实好多问题都可以用贪心来解决,用这个方法混个noi省二都不是问题,可惜了/(ㄒoㄒ)/~~我没能学到家。
今天来重新复习一下贪心算法!
贪心算法
我们首先要了解什么是贪心算法。
贪心贪心,就是说在当前的情况下,我们做出最符合现在最好的一步,没错,就是说我们只考虑当前,不从整体来考虑,这样我们的到的解就是局部最优解。
具体步骤一般是这样的:
1.我们将问题转化为若干个子问题
2.我们找到子问题的局部最优解
3.将局部最优解整合起来,得到问题的最优解
//这样看着是不是很简单,其实他看起来很简单,用起来一点也不难~
我们来以一道例题来说明贪心算法。
这道题,我们可以先知道,先让接水时间短的人来接水,这样后面人等待时间就比较短,假如10个人打水,那么第一个人打水的时候,后面九个人都要等待,题目是这个意思,那我们先让时间短的人来打水,这样不就是局部最优解,最后到最后一名的时候,那么就会变成全局最优解,你们觉得对不对呢?0.0
那么我们要先对这一堆人进行排序,排序的方法可以参考我上一篇文章,很具体很详细的讲述了如何实现数据排序!!挑战30天C艹基本入门(DAY3--数据排序)-CSDN博客
这里我们就直接用sort来排序。这样看下来,代码部分也不难,就是一个结构体排序问题。
#include<bits/stdc++.h>
using namespace std;
struct people{
int num;
int time;
}a[1000];
bool cmp(people a,people b)
{
return a.time<b.time;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>a[i].time;
a[i].num=i;
}
sort(a+1,a+n+1,cmp);
double sum=0;
for(int i=1;i<=n;i++)
{
cout<<a[i].num<<" ";
if(i<n)
sum+=a[i].time*(n-i);
}
cout<<endl;
printf("%.2lf",sum/n);
return 0;
}
这就是贪心里面比较经典的题目,当然思路也很直白,也很好实现。
那我们现在加大难度,看看下面关于整数区间的问题
这道题可能需要一点的思考时间,如何构建贪心模型呢?
我们由题目要首先得到一个隐藏的条件:如果存在这样的整数区间,那么他们必定排完序之后是相连接的。
我们可以按照区间的结束值,从小到大排序。
然后我们将第一个区间的结束值当作初始量,来进行贪心算法,让第一个区间的结束值,之后与每个区间的开始值对比。
如果大于的话我们不考虑,如果小于的话,我们将区间元素个数加1,然后再将第一个区间的结束值用我们小于的那个区间的结束值来代替。
之后就是在循环里找答案。
以此我们可以得出代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
int x;
int y;
}a[4000];
bool cmp(node a,node b)
{
return a.y<b.y;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y;
}
sort(a+1,a+1+n,cmp);
int t=1;
int o=a[1].y;
for(int i=2;i<=n;++i)
{
if(a[i].x>o)
{
t++;
o=a[i].y;
}
}
cout<<t;
return 0;
}
有了上面的基础,我们来看一道比较有难度的题目(学会了上面的其实也不难)
没错就是2002年的noi的题目:
我们首先要确定我们的贪心思路:
1.我们首先应该求出平均值,然后让牌数与平均值做差,我们可以得到正数,负数,和0,
2.0就说明已经均分过,可以将其跳过。
3.然后我们从左到右走一遍,让左边的变为平均值,然后右边的就成为了最左边,然后以此类推,实现贪心的闭环
代码部分也是比较好实现的:
#include<bits/stdc++.h>
using namespace std;
int a[1000];
int main()
{
int n;
cin>>n;
int step=0;
int sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
int ave=sum/n;
for(int i=1;i<=n;i++)
a[i]=a[i]-ave;
int i,j;
i=1;
j=n;
while(a[i]==0&&i<n)
i++;//找到第一个非零的数值
while(a[j]==0&&j>i)
j--;//找到最后一个非零的值
while(i<j)
{
a[i+1]+=a[i];//将第一个非零的值给下一个,然后上一个变成了第一个0
a[i]=0;
step++;
i++;//从下一个进行判断
while(a[i]==0&&i<j)//如果下一个为0之后,我们把它删去,继续循环
++i;
}
cout<<step;
}
这一类贪心的题目基本上属于中等偏上难度啦,写些题目起到学习和复习的作用还是很好的。
今天对贪心算法的讲解和复习就到此为止啦。
我们第五天再见啦!!!(谢谢大家支持啦)