3月20日一周学习总结
贪心算法
(个人对贪心算法的理解:以不断求解局部最优解的方式得到最终的总体解)
节目问题
节目问题的代表题目:给定一组节目的开始和结束时间,求最多能看多少节目。
此类问题一般都以结束时间进行排序,因为从局部来看,当前节目结束的越早,剩余的时间就越多,看更多节目的机会就越大,每次都选取最早结束的节目便可以保证所看的节目最多。
bool cmp(jiemu a,jiemu b)
{
if(a.en<b.en)
return 1;
else if(a.en==b.en)
{if(a.st<=b.st)
return 1;
else return 0;}
else return 0;
}
(先按结束时间升序排序,当节目结束时间相同时,便再按照开始时间排序)
罚分问题
罚分问题的代表题目:给定一组罚分和截止时间,求最少罚分数。
此类问题也是先进行排序,按时间升序排序,后按照罚分降序排序,当时间相同时,若当前罚分高于之前的最低罚分,与其进行对换,这样可以保证将罚分数降至最少。
(排序部分类似节目问题,不展示排序代码,以下是实现罚分统计的代码)
int z=1,f=0;
for(int i=1;i<=n;i++)
{
if(f<a[i].day)
{
b[z]=a[i].fen;
z++;
f++;
continue;}
else if(f==a[i].day)
{for(int j=1;j<z;j++)
{
if(b[j]<a[i].fen)
{
tem=a[i].fen;
a[i].fen=b[j];
b[j]=tem;
}
} s+=a[i].fen;}
}
(f用来判断天数是否重复,数组b则是记录之前的罚分,当出现罚分高的情况,便通过遍历数组b进行查找罚分最小的情况。)代码仍有待改进
类似问题还有超市利润最大化问题等。
区间调度问题
此类问题可以有多重提问方法,如寻找包含最少数的集合,或者重复最多线段,如搬桌子问题。
搬桌子问题:一条走廊搬桌子,走廊每段一次只能搬一张桌子,求最少搬桌子次数。
将每次搬桌子看做一条线段,线段最多重合数就是搬桌子所需的最少数。
关键部分实现代码:
for(int i=1;i<=n;i++)
{cin>>be>>en;
if(be%2==1)
be+=1;
if(en%2==1)
en+=1;
if(be>en)
swap(be,en);
for(int i=(be/2);i<=(en/2);i++)
a[i]++;}
for(int i=1;i<=200;i++)
{if(a[i]>maxn)
maxn=a[i];}
因为问题情境是走廊
如图,走廊为对称结构,因此奇数偶数相对应,可以只按一边走廊计算,即只计算偶数房间
价值最大化问题
此类问题包含题目繁多,如背包问题或Java been问题,个人认为是最典型的贪心问题,因为能够明显的体现出贪心的思想。
Java been问题:
for(int i=0;i<n;i++)
{
if(m>0)
{if(m>=a[i].mao)
{m-=a[i].mao;
sum+=a[i].been;}
else {
sum+=m*a[i].bili;
m=0;}}
else break;
}
按照兑换率进行降序排序。
数学类问题
此类问题一般难以一眼看出贪心思想,需要进行一定的推导。如物体相撞后变为一个物体,同时质量变为2* sqrt(m1*m2),求最后能得到的最小质量。
个人认为这个问题可以借助一次函数和平方根函数图像来进行判断,可以根据图像直观得出,大的数值开平方减少的越多,所以每次都让最大的元素进行开平方操作即可得到最小数。
可以使用优先队列来保证每次都是最大的数进行运算。
priority_queue<Node> q;
for(int i=1;i<n;i++)
{
double a=q.top().val;
q.pop();
double b=q.top().val;
q.pop();
node.val=2*sqrt(a*b);
q.push(node);
}
printf("%.3f\n",q.top().val);
q.pop();
}
删数问题
代表题目:给出一个多位数,删去指定个数的数字后得到的数为最小。
从第一位的俗话开始,若数字走向由升序变为降序或者没有下一个数,则删去这个数。
while(len--)
{
temp=t;
for(i=t;i<=m;++i)
{
if(num[temp]>num[i])
temp=i;
}
ans[k++]=num[temp];
m++;
t=temp+1;
}
i=0;
while(ans[i]=='0'&&i<k)//去除前导零
i++;
if(i==k)
printf("0\n");
else
{
for(;i<k;++i)
printf("%c",ans[i]);
printf("\n");
}
因为得数不能以0开头,所以需要去除前导0。
本周学习感悟与收获
这周是第一次接触算法,贪心作为一种基础的算法,既可以用来优化程序,又可以作为一种解题的思路,其重点在于找到贪心的方法,其次在于代码的实现,这周也通过vjudge接触了很多相关的题目,题型较为多变,但其统一具备从局部最优解出发进而得到最终解的思维模式,要掌握这类问题还需见识更多的题目,同时对于ac题目的代码还要进行优化和简化,达到最优解的目的。