noip2004-合并果子 2008.10.22
2016-02-05 11:29
417 查看
noip2004-合并果子 2008.10.22
不过其实这道题还可以用队列优化到O(n)的。
首先我们将n堆果子按照果子数递增的顺序排成一个序列a[1]‥a
,a[n+1]=∞,a[n+2]=∞。
b序列设为空(b[1]=b[2]=
‥b
=
∞,p=0)。
然后从a序列和b序列的第一个元素开始寻找合并方案(x=1,y=1)。
每一次合并方案不外乎三种:
合并两个初始堆(a[x]+a[x+1]);
一个初始堆与一个先前被合并的堆进行合并(a[x]+b[y]);
两个先前被合并的堆进行合并(b[y]+b[y+1]);
显然,本次合并耗费的体力值为min=MIN{a[x]+a[x+1],a[x]+b[y],b[y]+b[y+1]}
b序列新增加一个权值为min的元素(p=p+1,b[p]=min),
min累计入最小的体力耗费值ans(ans=ans+min),(我把这步漏了,wa了n次)
一定要看清题目!!!!
并按照下述方法移动指针x、y
如果采纳第一种合并方案,则a序列的指针x=x+2;
如果采纳第二种合并方案,则a序列的指针x=x+1,b序列的指针y=y+1;
如果采纳第三种合并方案,则b序列的指针y=y+2。
由于a序列和b序列是递增的,因此,上述指针移动的方法可以保证每次总是选择权值最小的两个节点进行合并。显然,进行了n-1次合并后得出的ans即为问题的解。
当然,要使得这道题要完全的变成O(n)的,最开始还必须用计数排序等线性时间排序。
合并果子队列优化
大家都知道,合并果子(NOIP2004)这道题可以用堆优化,时间复杂度是O(nlogn)。不过其实这道题还可以用队列优化到O(n)的。
首先我们将n堆果子按照果子数递增的顺序排成一个序列a[1]‥a
,a[n+1]=∞,a[n+2]=∞。
b序列设为空(b[1]=b[2]=
‥b
=
∞,p=0)。
然后从a序列和b序列的第一个元素开始寻找合并方案(x=1,y=1)。
每一次合并方案不外乎三种:
合并两个初始堆(a[x]+a[x+1]);
一个初始堆与一个先前被合并的堆进行合并(a[x]+b[y]);
两个先前被合并的堆进行合并(b[y]+b[y+1]);
显然,本次合并耗费的体力值为min=MIN{a[x]+a[x+1],a[x]+b[y],b[y]+b[y+1]}
b序列新增加一个权值为min的元素(p=p+1,b[p]=min),
min累计入最小的体力耗费值ans(ans=ans+min),(我把这步漏了,wa了n次)
一定要看清题目!!!!
并按照下述方法移动指针x、y
如果采纳第一种合并方案,则a序列的指针x=x+2;
如果采纳第二种合并方案,则a序列的指针x=x+1,b序列的指针y=y+1;
如果采纳第三种合并方案,则b序列的指针y=y+2。
由于a序列和b序列是递增的,因此,上述指针移动的方法可以保证每次总是选择权值最小的两个节点进行合并。显然,进行了n-1次合并后得出的ans即为问题的解。
当然,要使得这道题要完全的变成O(n)的,最开始还必须用计数排序等线性时间排序。
program fruit; const fin='fruit.in';fout='fruit.out'; const maxn=10005; var f1,f2:text; a,b:array[0..maxn]of longint; n,i,j,a1,a2,b1,b2,max:longint; procedure qsort(l,r: longint); var i,j,x,y: longint; begin i:=l;j:=r; x:=a[(l+r) div 2]; repeat while a[i]<x do inc(i); while x<a[j] do dec(j); if not(i>j) then begin y:=a[i]; a[i]:=a[j]; a[j]:=y; inc(i);dec(j); end; until i>j; if l<j then qsort(l,j); if i<r then qsort(i,r); end; procedure init; begin assign(f1,fin);reset(f1); assign(f2,fout);rewrite(f2); read(f1,n); fillchar(a,sizeof(a),0); for i:=1 to n do read(f1,a[i]); qsort(1,n); max:=0; end; procedure put(x:longint); begin inc(b2); b[b2]:=x; inc(max,x); end; procedure doit; var i,m1,m2,n1,n2:longint; begin a1:=1;a2:=n; b1:=1;b2:=0; fillchar(b,sizeof(b),0); for i:=1 to n-1 do begin m1:=a[a1];m2:=a[a1+1]; n1:=b[b1];n2:=b[b1+1]; if ((m2<=n1)and(m2<>0))or(n1=0) then begin put(m1+m2); inc(a1,2); end else if ((n2<=m1)and(n2<>0))or(m1=0) then begin put(n1+n2); inc(b1,2); end else begin put(m1+n1); inc(a1);inc(b1); end; end; writeln(f2,max); close(f1);close(f2); end; begin init; doit; end.
相关文章推荐
- PHP连接MSSQL方法汇总
- junit设计模式--命令者模式
- junit设计模式--命令者模式
- OpenGL编程指南之阅读笔记 第二章 状态管理和绘制几何物体
- Eclipse一步一步搭建SSM+Maven
- hadoop2.5.2安装部署
- SharePoint2016 New Feature (Preview) - 支持ODF File Template
- noip2005篝火晚会 2008.10.18
- SQL Server命令行
- noip2005-奖学金 2008.10.17
- 搭建lamp环境Q&A
- FFT与NTT
- Eclispe 生成JAVADOC 报java.lang.IllegalArgumentException解决方案
- Oracle12c Release1安装图解(详解)
- usaco numgrid 2008.9.29
- 系统设计以及javascript笔记:用户行为分析研究之数据采集
- 梯度下降优化算法概述
- IPython
- 应用沙盒
- SQL Server安装、使用报错及解决方案