离散化
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
离散化探究
@潘帕斯雄鹰
离散的题目在OI界还是占有一定地位的,而很多的离散化题目有很大程度上是贪心,也有很多是动态规划。离散是将数据经过关键字排序后以NP类问题处理。离散化是程序设计中一个非常常用的技巧,它可以有效的降低时间复杂度。其基本思想就是在众多可能的情况中“只考虑我需要用的值”。离散化可以改进一个低效的算法,甚至实现根本不可能实现的算法。要掌握这个思想,必须从大量的题目中理解此方法的特点。下面我从易到难选择了一些题目,希望对大家有所帮助。
离散化的定义如下:把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
其基本思想很简单,就是当输入数据的范围是无限空间,或者输入数据有很大量重复时,可以作一映射,从输入的无限空间到逻辑上的有限、有序的空间、同时避免重复。
声明:由于noip2005第二题river有很多版本的题解,故不在此篇中进行讲解。
本文章中有某些非原创部分,版权属于原作者。
锻炼计划(exercise.pas) noip普及组难度
身体是革命的本钱,OIers不要因为紧张的学习和整天在电脑前而忽视了健康问题。小x设计了自己的锻炼计划,但他不知道这个计划是否可行,换句话说如果计划不当可能会让他的体力超支,所以小x请你帮助他。
一天有1440分钟,所以小x列出的是这一整天第1至第1440分钟的计划。小x的体力用一个整数来表示,他会按照计划表进行锻炼,同时,每分钟小x的体力会自动增加1。如果某一分钟末小x的体力小于等于零,那么可怜的小x就累死了……
输入(exercise.in)
第一行是用空格分开的两个整数n,m,分别表示小x的初始体力值和计划的项目数量。
从第二行开始的m行,每行描述一个锻炼项目:名称、开始时间a、结束时间b、每分钟耗费的体力(用空格分隔),表示此项目从第a分钟初开始,第b分钟末结束。锻炼项目按照开始时间递增顺序给出,不会出现两个项目时间冲突的情况。
输出(exercise.out)
输出包括两行,如果计划可行,第一行输出"Accepted",第二行输出这一天过后最后剩余的体力;否则在第一行输出"Runtime Error",第二行输出在第几分钟累死。
样例
约定
0 0<=m<=500 所有中间值的绝对值不会超过2^31-1 每一个锻炼项目的名称不超过20个字符,其中不含空格。 题解:此题十分简单,来源为唐山OI 2005noip模拟赛的第一题,可以说是一个送分题目,如果每次查找开始锻炼最小的时刻,加上判断,复杂度为O(m^2)。但是如果我们对开始时间的大小进行关键字排序,那么可以说就把整天的计划全部映射在了一个数轴上,这样就实现了对数据的离散。然后再进行扫描,复杂度为O(mlogm+m)。从而在复杂度上进行了一个提升,当然,此题中数据范围较小,前者就可以AC。 program exercise; const success='Accepted'; failed='Runtime Error'; var n,m,i,j:longint; a:array[1..1440,1..2] of integer; h,time:array[1..1440] of longint; ch:char; inf,outf:text; procedure print1; begin assign(outf,'exercise.out'); rewrite(outf); writeln(outf,failed); writeln(outf,i); close(outf); end; procedure init; begin assign(inf,'exercise.in'); reset(inf); readln(inf,n,m); for i:=1 to m do begin ch:='x'; while ch<>' ' do read(inf,ch); readln(inf,a[i,1],a[i,2],h[i]); end; close(inf); end; procedure main; begin for i:=1 to m do for j:=a[i,1] to a[i,2] do time[j]:=h[i]; for i:=1 to 1440 do if time[i]=0 then inc(n) else begin inc(n); n:=n-time[i]; if n<=0 then begin print1; halt; end; end; end; procedure print; begin assign(outf,'exercise.out'); rewrite(outf); writeln(outf,success); writeln(outf,n); close(outf); end; begin init; main; print; end. 火烧赤壁(vijos某次模拟赛题目noip2004校门口外的树加强版)略高于noip普及组难度 描述Description 曹操平定北方以后,公元208年,率领大军南下,进攻刘表。他的人马还没有到荆州,刘表已经病死。他的儿子刘琮听军声势浩大,吓破了胆,先派人求降了。 孙权任命周瑜为都督,拨给他三万水军,叫他同刘备协力抵抗曹操。 隆冬的十一月,天气突然回暖,刮起了东南风。 没想到东吴船队离开北岸大约二里距离,前面十条大船突然同时起火。火借风势,风助火威。十条火船,好比十条火龙一样,闯进曹军水寨。那里的船舰,都挤在一起,又躲不开,很快地都烧起来。一眨眼工夫,已经烧成一片火海。 曹操气急败坏的把你找来,要你钻入火海把连环线上着火的船只的长度统计出来! 输入格式Input Format 第一行:N 以后N行,每行两个数:Ai Bi(表示连环线上着火船只的起始位置和终点,-10^9<=Ai,Bi<=10^9) 输出格式Output Format 输出着火船只的总长度