ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:94.08KB ,
资源ID:3834183      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/3834183.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(JSOI09第一轮省队选拔试题解题报告.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

JSOI09第一轮省队选拔试题解题报告.docx

1、JSOI09第一轮省队选拔试题解题报告JSOI09第一轮省队选拔试题解题报告By sx349 一、 二叉树问题【问题描述】如下图所示的一棵二叉树的深度、宽度集结点间距离分别为:深度:4 宽度:4(同一层最多结点个数)结点间距离: 为8(32+2=8) 为3(12+1=3)注:结点间距离的定义:由结点向根方向(上行方向)时的边数2, 与由根向叶结点方向(下行方向时的边数之和)。【 输 入 】输入文件第一行为一个整数(1n100),表示二叉树结点个数。接下来的n-1行,表示从结点x到结点y(约定根结点为1),最后一行两个整数u、v,表示求从结点u到结点v的距离。【 输 出 】三个数,每个数占一行,

2、依次表示给定二叉树的深度、宽度及结点u到结点v间距离。【 样 例 】输入:101 21 32 42 53 63 75 85 96 108 6输出:448【算法分析】这道题主要考察了对于二叉树的了解,其次对于题意的正确理解在这道题中也起到了非常大的作用。首先我们来看这一句话:“接下来的n-1行,表示从结点x到结点y(约定根结点为1)”。分析这句话后可知,在其后给出的x,y并不是有序的(不一定x就是y的父结点)。忽略这一点将会使程序出现致命性的错误。了解这一点后,程序就很简单了。我们用领接矩阵来记录所有相连的结点(标记所有的connectx,y以及connecty,x),由于已知结点1必然为根结点

3、,所以从结点1开始进行一次DFS即可建树。在进行DFS前,我们再回头看一下题目,我们要求的是:“给定二叉树的深度、宽度及结点u到结点v间距离。”深度我们用DeepI来记录,宽度就是DeepI中出现最多的那个数的出现次数(比如Deep数组中有3个4、4个3、2个2、1个1,那么宽度就是出现最多的数(3)的出现次数(4),而结点间距离就是(Deep起始结点-1)*2+Deep结束结点-1(因为我们要求的是某一点到根结点的线段数,所以比其深度小1)。这样分析以后,我们只需在DFS的过程中将每棵树的深度记录下来,然后不断判断MAX值即可。【程序清单】Program Tree;Var Con:Array

4、1.100,1.100 of Boolean; DeepSum,Deep:Array1.100 of Longint; A,B,N,I,MaxDeep,MaxBroad:Longint; Procedure Search(Now:Longint); Var I:Longint; Begin For I:=1 to N do If ConNow,I and (DeepI=0) Then Begin DeepI:=DeepNow+1; Search(I); End; End;Begin Assign(Input,Tree.in); Assign(Output,Tree.out); Reset(In

5、put);Rewrite(Output); Read(N); For I:=1 to N-1 do Begin Read(A,B); ConA,B:=True; ConB,A:=True; End; Read(A,B); Deep1:=1; Search(1); For I:=1 to N do Begin Inc(DeepSumDeepI); If DeepSumDeepIMaxBroad Then MaxBroad:=DeepSumDeepI; If DeepIMaxDeep Then MaxDeep:=DeepI; End; Writeln(MaxDeep); Writeln(MaxBr

6、oad); Writeln(DeepA-1)*2+DeepB-1); Close(Input); Close(Output);End.二、 照明灯【问题描述】在一条直线上,有n个三角形(假设其为n座山峰)。对于每座山峰均有四个参数(x,y,d,h),其中:x表示山峰前点,y表示山峰后点,d表示山峰位置,h表示山峰高度。这四个参数均为整数(1x,y,d,h1000)。同时,约定山峰的底角均为小于90的角。给出一个位置P,在P处有一个灯杆,灯杆上部装有一个灯泡。【编程任务】灯最少离地面多高时,才能照到全部不被山峰覆盖的地面。上图中的OA,BC,FX即使不被山峰覆盖的地面。【 输 入 】输入文件的第

7、一行有三个整数n,X,P(1n100),接下来的n行,每行有四个参数,用以表示一座山峰(数据间用一个空格分隔)。【 输 出 】一个实数(保留小数二位)。表示满足要求时,灯离地的最小高度。【 样 例 】输入:2 10 51 3 2 16 9 7 1输出:400【算法分析】首先考虑下这个问题:什么地方的地面最难被照到?显然,是紧贴着山脚的那个点。所以,我们只要考虑每个空当(即“不被山峰覆盖的地面”)的左右两个端点能否被找到就可以了。怎么确定这个端点呢?由于山峰的位置已经告诉你了,我们用一个布尔型数组StateI来记录以I为左端点,长度为1个单位的线段是否被山峰覆盖。然后扫一遍整个数组,将所有的需要

8、计算的点挑出来计算。接下来我们看根据这个点怎么计算它所需要的灯泡高度。可能我们会先产生这样的想法:我们现在把所有的组成山的两条线都延长,这些延长线必然在直线x=P这条线上有交点。我们只要找出这些交点中y轴坐标最大的那个点,它就是Q点。显然,这个算法是有瑕疵的,比如下面这张图:显然,在这种情况下,灯的位置并不在山峰的延长线上。上述思想的理论基点在于这样一个想法:每一个被照亮的山脚最低需要的灯泡高度为将这个山脚所贴的山峰那条边延长后与直线x=p的交点。这个想法有一个错误的地方在于,当山峰的这条边延长时,如果与另一座山峰相交,光线就会被另一座山峰挡住。所以我们将这个想法进一步改进一下:假设这个点在P

9、的左侧(右侧也可依样处理),那么我们将这个点和P点左侧的所有山峰(这里可以小小的优化为这个点与P点间所有的山峰)顶端连一条线,然后延长到P,选择其中的最高点。这样可以保证从这个点射到某个山脚的光线不会被阻挡住。如何求延长线与直线x=P的交点呢?我们应用相似三角形的原理,假设当前点横坐标为now,取第I个山峰,则有|now-p|:|now-di|=height:hi(height为所需山峰高度),因此有height=(|now-p|*hi)/|now-di|。最后选择所有height中的最大值即为灯泡的最小值。【程序清单】Program Lamp;Var x,y,N,L,P,I,J,K:Long

10、int; d,h:Array1.100 of Longint; State:Array-1.1000 of Boolean; Min:Extended; Procedure Q_Sort(Left,Right:Longint); Var I,J,Mid:Longint; Begin I:=Left; J:=Right; Mid:=d(I+J) Div 2; Repeat While dIMid do Dec(J); If IJ; If ILeft Then Q_Sort(Left,J); End; Procedure Search(Now:Longint); Var I:Longint; He

11、ight:Extended; Begin If NowMin Then Min:=Height; End Else For I:=K to N do Begin Height:=hI/(now-dI)*(p-now); If HeightMin Then Min:=Height; End; End;Begin Assign(Input,Lamp.in); Assign(Output,Lamp.out); Reset(Input); Rewrite(Output); Read(N,L,P); For I:=1 to N do Begin Read(x,y,dI,hI); For J:=x to

12、y-1 do StateJ:=True; End; Q_Sort(1,N); I:=1; While dI=p do Inc(I); K:=I; State-1:=True; StateX:=True; Min:=0; For I:=0 to X-1 do If not StateI Then Begin If StateI-1 Then Search(I); If StateI+1 Then Search(I+1); End; Writeln(Min:0:2); Close(Input); Close(Output);End.三、 数列计数【问题描述】由1,2,3,P(P9),这P个数字组成

13、长度为L的数列(1L30)。【编程任务】要求不能有K个或大于K个1相连的数列个数(1KL)。【 输 入 】仅一行,包含有三个整数(用一个空格分开),分别表示P、L、K。【 输 出 】一个整数。表示合理的数列个数。【 样 例 】输入:3 3 2输出:22【样例说明】1 2 1 2 1 2 3 1 21 2 2 2 1 3 3 1 31 2 3 2 2 1 3 2 11 3 1 2 2 2 3 2 21 3 2 2 2 3 3 2 31 3 3 2 3 1 3 3 1 2 3 2 3 3 2 2 3 3 3 3 3(合理的数列个数共22种)。【算法分析】显然这是一道数学题,我们就应该考虑用数学方法

14、来解决。我们很容易得到这样的一个递推式:设为长度为n,且末尾有t个1的数列总数。那么有递推式:最后求。初始边界为显然,这个递推式的复杂度为O(L*K*K)即O(L3)左右,因为L仅为30,因此即使再加上高精度运算,这个复杂度还是可以忍受的。但是在二维数组中使用高精度有些繁琐,所以我们还可以进一步推导,将(1)式代入(2)式可以得到:我们可以将这个等式转化为一维的式子,即:其中表示长度为i,末尾不以1结尾的数列个数。最后求的值相应变为。初始边界变为空间复杂度降为O(L),时间复杂度也降为O(L*K)。为了获得更快的速度,进一步推导该式子,有:该式子的适用范围为n2,所以边界条件增加1个为(因为无

15、法由该式推出)由于K不等于1,所以这个边界是可以的。由于这道题最后的数据极大(约为4*1019),所以必然考虑要用高精度计算,为了简化运算,我们可以发现,当nk时,后面的始终为0,也即有:这样,可以省去数组f中的负数部分。这样一来,时间复杂度进一步降低为O(L),数据量再大一些也可以承受。显然,根据该递推式可以考虑O(1)的算法,但那需要更大量的数学推导,限于篇幅,在这里就不进一步赘述了。有兴趣的同学可以进一步自行研究。【程序清单】Program Count;Type Num=Array0.100 of Integer;Var P,L,K,I:Longint; F:Array0.31 of N

16、um; Ans:Num; Procedure Cheng(Str:Num;N:Longint;Var Str1:Num); Var I:Longint; Begin For I:=1 to Str0 do Str1I:=StrI*N; For I:=1 to Str0 do Begin Str1I+1:=Str1I+1+Str1I Div 10; Str1I:=Str1I Mod 10; End; If Str1Str0+10 Then Str10:=Str0+1 Else Str10:=Str0; End; Procedure Add(Str:Num); Var I,T:Longint; B

17、egin If Str0Ans0 Then T:=Str0 Else T:=Ans0; For I:=1 to T do AnsI:=AnsI+StrI; For I:=1 to T do Begin AnsI+1:=AnsI+1+AnsI Div 10; AnsI:=AnsI Mod 10; End; Ans0:=T; If AnsT+10 Then Ans0:=T; End; Procedure Minus(Str,Str1:Num;Var Str2:Num); Var I:Longint; Begin For I:=1 to Str0 do Str2I:=StrI-Str1I; For

18、I:=1 to Str0 do While Str2IK Then Begin Cheng(FI-K-1,P-1,F31); Minus(FI,F31,FI); End; End; Fillchar(Ans,Sizeof(Ans),0); For I:=L-K+1 to L do Add(FI); For I:=Ans0 downto 1 do Write(AnsI); Close(Input); Close(Output);End.四、 谜题【问题描述】有些人花很多时间去解各种各样的谜题,这里要考虑的一种典型的谜题看上去是这个样子的:这里给出了一个包含各种符号的等式(包括横向等式与纵向等式)

19、,必须找到将符号一一对应地替代为数字0,9的方法。如果你曾经尝试过解这种谜题,你就会发现这是一件多么烦琐的事情。【编程任务】给你一组包含符号A,B,J的等式。请你找到将符号替代位数字的方法,使得所有的等式同时成立。所有有数字组成的数都是正的,并且第一个数字都不是0。如果有多个解法存在,则只打印出将替换后的数字串看成一个整数是数值最小的一组解,如:解 2345678901 和解 1987654320 都满足条件,则只打印出1987654320,因为它在“数值”上最小。【 输 入 】输入由一行单独的整数n开始(n代表等式的个数,1n10)。接下来是n个等式。每个等式的语法如下:equation =

20、 argument1 +|-|*|/ argument2 - resultargument1 = digit digit*argument2 = digit digit*result = digit digit*digit= A|J注意:并不是所有A到J的符号都会出现在等式中。然而,如果其中一个符号出现了,那么所有在字母排序上比它小的符号就同样会出现。所有出现的数最多有11个数字(即最多是11为整数)。【 输 出 】输出仅一行,格式如下:按字母表顺序排列的所有出现字符一个箭头-对出现的符号在树枝上最小的替换。如果没有解,则输出一行No solution【 样 例 1 】输入6EBCE/CED=

21、AEFBGB-FHBG=ADCDIAA-GIHJ=FJHFEBCE-FBGB=DIAACED+FHBG=GIHJAE*ADC=FJHF输出ABCDEFGHIJ-1746823509【 样 例 2 】输入1A+A=AA输出A-No solution【算法分析】这道题很眼熟,和“虫食算”很相似,而且比“虫食算”还稍简单一点。显然这道题的做法应该是按字母顺序DFS搜出第一个解即输出。(因为题目要求字典序,所以按字母顺序搜索,显然第一个解组后得到的数字序列比后面的小)搜索时使用函数search(x,S)来进行,其中x表示当前搜索第x个字母,S表示当前还未检查过的式子的集合。函数中要进行:判断剩下式子中

22、再搜出前x-1个字母后是否成立,以及给第x个字母赋值。S的作用在于,当我进行下一步搜索时,不需要将n个式子全部搜索一遍,而只需搜索剩余没检查过的式子即可。鉴于集合的运算相对比较不变,我们考虑用一种类似Hash的方法:我们用数字来表示这个集合S,将该数字表示为二进制后,它的倒数第i位表示第i各式子的状态,这样每种状态对应一个数字,显然,由于式子总数为11,所以有S1024。因为将S作为数字,所以相应的检查运算就要利用数字之间的运算。我们利用PASCAL中的位运算来进行:加入第i个式子:S:=S+2i减去第i个式子:S:=S-2I判断第i个式子是否在S中:S and 1 shl(i-1)0接下来考

23、虑剪枝,显然我们可以看见一个基本的剪枝,当某个式子A op B = C 的所有字母值都已经搜索出来之后,我们可以判断这个式子的正确性,如果正确,则在S中删除该式子(已判定必正确)否则回溯(显然,这个式子中有些地方不正确)进而达到剪枝的目的。这个剪枝是一个很基本的剪枝,很容易想到,而且比较容易实现(通过PASCAL中字符串函数的应用)。但是显然这个剪枝的力度不强,比如说当每个式子都有10个未知数时,显然要将所有字母都搜索出来才能利用它来剪枝,此时的时间复杂度仍然是没有剪枝时的O(n!)左右。我们可以将这个剪枝拓展一下。比如式子A op B = C中,如果A和B的值都已经搜索出来了,而C还没有全部

24、搜索出来(如果全部搜索出来就可利用上面那个较弱的剪枝)那么显然我们可以计算A op B的值与C进行比较。如果与已搜索出的值不相同,那么就可以直接回溯到上层,如果相同,则可以直接确定C中剩下字母的值(显然为了式子正确,C必然为A op B的值),并将该式子从S中去掉。这个剪枝的力度比上一个强很多,同时也可以减少搜索的次数(因为已经确定了后面的值)。但我们还可以将这个剪枝进一步拓展:当A,B,C中有两个计算出来后,可以将另一个计算出来,判断正确性。正确,则可以确定一部分未确定的值,不正确,则立刻回溯。这一步扩展后可以使搜索速度加快更多。另一个重要的剪枝是通过不等式剪枝。如搜索中有式子3G*2DE=

25、3F2C,显然,这个式子后面无论搜索出什么值都不会成立,这是我们一眼就看得出来的,那如何让电脑来判断呢?我们先把左边所有的未知数都换成9,那么左边可以达到的最大值就是39*299=11661,再把所有未知数换成1,那么左边可以达到的最小值就是31*211=6541。再看右边,将所有未知数换成9,得最大值3929;再把所有未知数换成1,得最小值3121。显然,如果左边的最大值(这里是11661)小于右边的最小值(3121)(这里显然是大于的),或者左边的最小值(6541)大于右边的最大值(3929)(显然这一点成立),那么也可以立刻回溯到上一层。这个剪枝可以运用在加、减、乘三种运算上,但是除要运

26、用到实数,所以比较麻烦。如何克服这一点呢?因为减法是加法的逆运算,除法是乘法的逆运算,所以我们可以在一开始就将减法和除法与处理为加法和乘法,这样在处理时,只需要处理乘法和加法的情况就可以了。【程序清单】(鉴于篇幅过长,在此略去)小结在这次JSOI09省对第一轮选拔的试题中,只有最后一题需要复杂的思考过程,另三道题目相对来说难度不大。但是在选拔赛过程中,需要时刻对于题目和自己的程序有着清醒的认识。譬如我在比赛中,对于第一题中的输入理解有误,没有考虑到给出的两个结点并不一定是按父子结点排好的,所以直接考虑使用并查集来做。显然,这一算法必然得不到满分。而第二题中,对于灯泡要照亮的部分要判断清楚,尤其

27、是这道题中给出的山峰是以点为标记的,而要照亮的地方则是线段。第三题的递推公式则只要能够发现第一个公式就可以完成这个题目了,但是如果能够再花一点时间往后推导,那么效率肯定更高。最后一题中的两个大剪枝(依据等式性质和不等式性质)相对来说比较难想到,在比赛中应该有选择性地选择变成容易较简单的剪枝,比如前一个剪枝的基础样式比较容易想到,在这个基础上,如果时间充分那么完全可以考虑进一步深入,否则的话也应该果断放弃(因为深入后的编程复杂度由于修改处的增多而大大增加)。这也是在比赛中应该做到的。总的来说,这一次比赛对我来说是一次很大的磨炼。在这次比赛中,充分暴露出我在正式比赛中对于细节相当不注意的缺点,这一点对于比赛是极为致命的。希望在以后的训练中,我能够在这一点上有所改善。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1