贪心算法
一周做题的思路心得,和思考的方面
储存酸奶,花费最少金钱问题
类型为:每一周都要支付一定量的酸奶,每一周的价格有所波动,但可以把酸奶储存起来,每周每单位的酸奶要有支付一定的费用,问花费是的金钱最少是多少
思路每一周的酸奶价钱和数量的是不一定的,且储存酸奶只能留到下几周使用,所以不需要进行排序,只需要考虑如何让当周酸奶价格最少,则需要让当周的价钱和上一周的价格*加上储藏的费用作比较就可以了
#include <iostream>
#include <algorithm>
using namespace std;
struct f
{
int c;//钱
int y;//数量
}a[10005];
int main()
{
int n,s;
cin>>n>>s;
for(int i=0;i<n;i++)
{
cin>>a[i].c>>a[i].y;
}
long long sum=0;
int t=a[0].c;
for(int i=0;i<n;i++)
{
t=min(t+s,a[i].c);//取出二者最小值
sum+=t*a[i].y;
}
cout<<sum<<endl;
return 0;
}
雷达问题
问题描述:一个坐标系,在x轴的上半轴有若干个小岛,在x轴上建立半径为r的小岛,问最少需要几个雷达覆盖除全部的雷达
解决思路:可以用逆向思维把雷达建在小岛上,用勾股定理求出和x轴的交点,并用结构体储存下来。根据贪心,根据结束第一个最小点的区间为开始,遍历所有的区间,在刚开思考的时候只想到了两种情况,区间有交集,和区间没交集。没交集更新标记点,雷达数加一,有交集则跳过。但这样是错误的,漏掉了一种情况,结束有交集的情况下还有两种情况一个是二者只是相交,还有我漏掉的二者包含的这种情况,则解决的方法谁当二者包含的时候,把标记点更新为被包含在内的小区间
代码实现为
1using namespace std;
struct ll
{
double be;
double en;
}a[1005];
bool cmp(ll a,ll b)
{
return a.be<b.be;
}
int main()
{
int n,d,c=0;
while(cin>>n>>d)
{
if(n==0&&d==0)
break;
int x,y,flag=1,sum=1;
double t;
c++;
for(int i=0;i<n;i++)
{
cin>>x>>y;
a[i].be=x-sqrt(double(d*d-y*y));
a[i].en=x+sqrt(double(d*d-y*y));
if(y>d)
flag=0;
}
if(flag==0)
{cout<<"Case "<<c<<": "<<-1<<endl;continue;}
sort(a,a+n,cmp);
t=a[0].en;
for(int j=1;j<n;j++)
{
if(a[j].en<=t)
t=a[j].en;//包含的情况,更新标记点
else
if(a[j].be>t)
{
sum++;
t=a[j].en;
}
}
cout<<"Case "<<c<<": "<<sum<<endl;
}
return 0;
}
装下不同体积的小箱子,需要箱子最少问题
问题描述:有116到666的6种箱子,需要用666的箱子装起起来,问至少需要几个666的箱子
解题思路:因为他们都高度都是一样的,所以可以把它们看做成面积的问题,我是从每个箱子进行分析的,首先是6* 6的箱子很明显需要一个箱子把它装下且没有多余的空间,5 5的箱子在需要一个箱子装下后多余的空间可以放入1 1的箱子,4 4的箱子需要一个箱子装下去后剩下优先装22的箱子在考虑11的箱子,一个箱子可以装进去4个33的若有剩余的空间操作方法和44的一样,但需要注意的是最后一个箱子装了几个33的小箱子,只会影响22的能装几个,剩余22的只需要考虑剩余的位置装几个11的就可以了。如何想到不难,就是写的代码会非常的繁琐,不注意就会漏掉几种情况
1using namespace std;
int a[7];
int main()
{
while(cin>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6])
{
int sum=0,he=0,s=0;
for(int i=1;i<=6;i++)
{
sum+=a[i];
}
if(sum==0)
break;
he+=a[6];
he+=a[5];
a[1]-=11*a[5];
he+=a[4];
for(int j=0;j<a[4];j++)
{
if(a[2]>5)
a[2]-=5;
else if((a[2]<=5)&&(a[2]>0))
{a[1]-=4*(5-a[2]);
a[2]=0;
}
else if(a[1]>0)
a[1]-=20;
}
he+=(a[3]+3)/4;
s=a[3]%4;
if(s==3)
{
if(a[2]>0)
{a[2]-=1;
a[1]-=5;}
else
{a[1]-=9;}
}
if(s==2)
{
if(a[2]>0)
{a[2]-=3;
a[1]-=6;}
else
{a[1]-=18;}
}
if(s==1)
{
if(a[2]>0)
{a[2]-=5;
a[1]-=7;}
else
{a[1]-=27;}
}
s=a[2]/9;
he+=s;
s=a[2]%9;
if(s>0)
{
a[1]-=4*(9-s);
he++;
}
while(a[1]>0)
{a[1]-=36;
he++;
}
cout<<he<<endl;
}
return 0;
}
锯木块问题
问题描述:有若干个不同重量和长度的木块,用机器加工,如加工的木块的长度和重量都比上一块木块大,则不需要消耗时间,否则需要一分钟去调试机器。
思路:如果下一个的木块比这个质量和长度都大,那么不需要多费实际,那么把重量升序排列这样,只需要看长度就可以了,如果比上一个大就跳过,如果小则时间加一,更新标价点。然而这种思路是错误的,当前我们已经解决掉了重量,如果我们在找到长度是递增的就可以不调试机器,这才是正确的贪心,所以我们需要找到长度有几个升序序列,有几个升序序列就有需要调试几个机器
11using namespace std;
struct f
{
int b;
int e;
}a[10005];
bool cmp(f aa,f bb)
{
if(aa.b!=bb.b)
return aa.b<bb.b;
else
return aa.e<aa.e;
}
int main()
{
int x;
cin>>x;
while(x--)
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i].b>>a[i].e;
}
sort (a,a+n,cmp);
int sum=0,t;
int p[10005]={0};
for(int i=0;i<n;i++)
{
t=a[i].e;
if(p[i]==1)
continue;
for(int j=i+1;j<n;j++)//从第一个开始遍历
{
if(a[j].e>=t&&p[j]==0)//用标记来判断他是否用过,和是否满足条件,并遍历他向后所有的
{
p[j]=1;
t=a[j].e;
}
}
sum++;
}
cout<<sum<<endl;
}
return 0;
}
一周的总结和感想:
经过这次的错题感觉对贪心算法的有了更生的认识,找到了思考问题的方法,和切入点。在整理问题回顾解题思路的时候发现,如何找到最优的方法,可能会从 排序的方法,和从哪里开始遍历全部的出发点,和最重要的在遍历的过程中需要考虑有几种可能出现的的情况和特殊情况。比如这次的雷达和木块问题,结束漏掉了几种情况,而锯木块的问题,如何遍历所有的情况,则该题目的思路就在题目中,所以认真读题和在题目中找到解题的方法也就很重要了。当出现问题的时候对自己代码从头分析,找到是不是漏掉的情况,货值思路上出现了什么问题。而且一种问题可能会有不同的解题方法,在自己的思路实现后,多多了解其他解决思路会有更多的收获,和自己的思路比起来也会使自己的代码多多优化。