2015NOIP模拟赛(一) 试题及解析

 小车问题

car.pas

 

【问题描述】

甲、乙两人同时从A地出发要尽快同时赶到B地。出发时A地有一辆小车,可是这辆小车除了驾驶员外只能带一人。已知甲、乙两人的步行速度一样,且小于车的速度。问:怎样利用小车才能使两人尽快同时到达。

【输入】

仅一行,三个数据分别表示AB两地的距离s,人的步行速度a,车的速度b

【输出】

两人同时到达B地需要的最短时间。

【样例】

car.in

120 5 25

car.out

9.6000000000E+00 

两数之和

pair.pas

【问题描述】

 我们知道从n个非负整数中任取两个相加共有n*(n-1)/2个和,现在已知这n*(n-1)/2个和值,要求n个非负整数。

【输入】

输入文件仅有一行,包含n*(n-1)/2+1个空格隔开的非负整数,其中第一个数表示n(2,其余n*(n-1)/2个数表示和值,每个数不超过100000

【输出】

输出文件仅一行,按从小到大的次序依次输出一组满足要求的n个非负整数,相邻两个整数之间用一个空格隔开;若问题无解则输出“Impossible”

【样例】

pair.in

3 1269 1160 1663

pair.out

383 777 886

 

血缘关系

family.pas

【问题描述】

我们正在研究妖怪家族的血缘关系。每个妖怪都有相同数量的基因,但是不同的妖怪的基因可能是不同的。我们希望知道任意给定的两个妖怪之间究竟有多少相同的基因。由于基因数量相当庞大,直接检测是行不通的。但是,我们知道妖怪家族的家谱,所以我们可以根据家谱来估算两个妖怪之间相同基因的数量。

妖怪之间的基因继承关系相当简单:如果妖怪C是妖怪AB的孩子,则C的任意一个基因只能是继承AB的基因,继承AB的概率各占50%。所有基因可认为是相互独立的,每个基因的继承关系不受别的基因影响。

现在,我们来定义两个妖怪XY的基因相似程度。例如,有一个家族,这个家族中有两个毫无关系(没有相同基因)的妖怪AB,及它们的孩子CD。那么CD相似程度是多少呢?因为CD的基因都来自AB,从概率来说,各占50%。所以,依概率计算CD平均有50%的相同基因,CD的基因相似程度为50%。需要注意的是,如果AB之间存在相同基因的话,CD的基因相似程度就不再是50%了。

你的任务是写一个程序,对于给定的家谱以及成对出现的妖怪,计算它们之间的基因相似程度。

【输入】

第一行两个整数nkn2n300)表示家族中成员数,它们分别用1, 2, ……, n来表示。k0kn-2)表示这个家族中有父母的妖怪数量(其他的妖怪没有父母,它们之间可以认为毫无关系,即没有任何相同基因)。

接下来的k行,每行三个整数a, b, c,表示妖a是妖怪bc的孩子

然后是一行一个整数m1mn),表示需要计算基因相似程度的妖怪对数。

接下来的m行,每行两个整数,表示需要计算基因相似程度的两个妖怪。

你可以认为这里给出的家谱总是合法的。具体来说就是,没有任何的妖怪会成为自己的祖先,并且你也不必担心会存在性别错乱问题。

【输出】

m行。可k行表示第k对妖怪之间的基因相似程度。你必须按百分比输出,有多少精度就输出多少,但不允许出现多余的0(注意,0.001的情况应输出0.1%,而不是.1%)。具体格式参见样例。

【样例】

family.in

7 4

4 1 2

5 2 3

6 4 5

7 5 6

4

1 2

2 6

7 5

3 3

 

 family.out

0%

50%

81.25%

100%

解析:

 

1、小车问题

最佳方案为:甲先乘车到达K处后下车步行,小车再回头接已走到C处的乙,在D处相遇后,乙再乘车赶往B,最后甲、乙一起到达B地。这样问题就转换成了求K处的位置,我们用二分法,不断尝试,直到满足同时到达的时间精度。算法框架如下:

1)输入sab

2c0:0c1:sc:(c0+c1)/2

3)求t1t2

4)如果t1,那么c:=(c0+c)/2

否则c:(c+c1)/2

反复执行(3)(4),直到abs(t1-t2)满足精度要求(即小于误差标准)。

2、两数之和

本题的规模只有10,看似一道搜索题。其实不然,搜索固然有可能出解,但是本题是有多项式级算法的。本题的难点就在于要理清这看似混乱的n(n-1)/2个“和”的关系,从中寻找突破口。

那么,突破口在哪里呢?n(n-1)/2个“和”是任意给出的,并未按照什么指定的顺序,所以从表面上看这些数(和)之间似乎没有什么区别。当然,我们必须在这些数(和)中制造出一些区别来,因为没有区别我们也就无从下手。对什么信息也没有的一些数,惟一可以制造出的区别就是它们之间的大小关系。根据数的大小关系,我们可以对这n(n-1)/2个数排序。排完序后,可以成为突破口的无非就是那么几个,最小的数(和)、最大的数(和)、中位数??我们不可能随便找一个数出来作为突破口,因为随便找一个数的话,大小关系就失去意义了。所以,这时我们需要注意的只有这么几个数了:最小的数(和)、最大的数(和)和中位数。

中位数看上去似乎也很难成为突破口,因为我们无法预知中位数是哪两个数的和。而最小、最大的两个数(“最小的和”与“最大的和”)则不同,最小的和必然是最小的两个数之和,最大的和必然是最大的两个数之和。由问题对称性,最小与最大其实是等价的,所以我们可以只考虑最小的情况,解决了最小,最大也就相应解决了。

最小的和是最小的两个数之和,这是一条已经确定的与最小的两个数相关的信息。当然,就凭这些信息,我们还是无法知道最小的两个数究竟是多少,这是我们目前面临的一个障碍。我们不妨先跳过这个障碍,考虑以后的问题。我们可以假设已经知道最小的数的大小,这样我们又可以很顺利的知道次小的数是多少了(最小的和-最小的数)。

 知道最小的两个数的大小对我们有什么好处呢?其实关键是知道最小的数是多少,这是至关重要的,因为很多特殊的和都与最小的数有关。试想,我们知道了最小的两个数,也就确定了一个和(最小的和)。把这个“和”从n(n-1)/2个和中去掉,剩下的n(n-1)/2-1个和中又会产生新的最小的和。这个新的最小的和是哪两个数的和呢?应该是最小的数与第三小的数的和。由于我们假设已经知道最小的数,我们自然就可以通过作差得到第三小的数了。

得到前三小的数后,我们就确定了3个“和”了。籽这三个“和”从n(n-1)/2个和中去掉,剩下的n(n-1)/2-3个和中又会产生新的最小的和。这个新的最小的和必然是最小的数与第四小的数的和。由于最小的数已知,第四小的数就可以算出了。更一般的情况,知道了前k小的数,那么我们就确定了k(k-1)/2个和了。将这k(k-1)/2个和从n(n-1)/2个和中去掉,剩下的n(n-1)/2-k(k-1)/2个和中又会产生新的最小的和。这个新的最小的和必然是最小的数与第k+1小的数的和;由于最小的数已知,第k+1小的数就可以通过作差得到。

如此,在知道了最小的数的情况下,不断的从当前最小的和入手,就可以从小到大依次把所有的数都推算出来了。

不过,有一点还是需要注意的,前面所有的推导都是建立在最小的数已知的情况下的,但实际情况是最小的数未知。所以,我们还需要创造条件,使最小的数由未知变为已知。

一个简单而可行的方法就是枚举最小的数。简单就不必说了,为什么说枚举是可行的呢?因为题目规定所有的数都不超过100000,因此总共需要枚举的方案数最多只有100000。而在知道最小的数的情况下,推算出其他数的代价是O(n2)n?10100000*102的计算代价是可以承受的。最后,我们总结一下前面得到的算法。

1)枚举最小的数;

2)根据最小的数和最小的和,得到次小的数;

3)由前k小的数推出第k+1小的数。

算法的时间复杂度是O(Cn),其中C表示数值的大小。

从本题的解题过程中,我们看到其中最关键的一步就是以最小的和作为突破口。在解决数学问题的时候,很多情况下从为数不多的信息中寻找突破口是至关重要的。找到了突破口,问题本身也就迎刃而解了。

3.血缘关系

本题是一道概率计算题,但这个概率计算又是建立在Family Tree模型上的。Family Tree是一个有向无环图,有明显的阶段性(辈分关系),而且没有后效性(没有人可以成为自己的祖先),符合动态规划模型的基本条件。因此,应该可以套用类似动态规划的方法来解决。

我们先来明确一下相似程度的计算方法。假设我们要求的是AB的相似程度(设为P(A, B)),那么有两种情况是显然的:

1A=B:P(A, B)=1

2AB无相同基因:P(A, B)=0

这是计算其他复杂情况的基础。因为动态规划就是从一些特定的状态(边界条件)出发,分阶段推出其他状态的值的。

再来看一般的情况,设A0A1A的父母。那么,取概率平均情况,A拥有A0A1的基因各占一半。假设A0B的相似程度为P(A0, B)A1B的相似程度为P(A1, B),那么P(A, B)P(A0, B)P(A1,B)之间应该是一个什么样的关系呢?很容易猜想到:

P(A, B)=(P(A0, B)+P(A1, B))/2

但是,这只是一个猜想。要让它变为一个结论还需要证明:

我们用归纳法来证明。

首先,我们知道,在这个问题中不同基因都是从特定的祖先传下来的,不会出现同一个基因采自不同的祖先的情况(注:这里的祖先是指那些没有父母的妖怪)。所以,如果AB有相同的基因,这些基因必然来自同一个祖先。这里,我们最想说明的是,祖先那代是不存在两个人,它们之间不同的基因相同的概率不一样,因为它们相同的概率都是0

现在,A有祖先A0A1A0A1B的相似程度分别为P(A0, B)P(A1, B)。从祖先一代开始归纳,可由归纳假设A0BA1B之间每个基因相同的概率都是一样的,分别都是P(A0, B)P(A1, B)A的单个基因,它可能是继承A0的,也可能是继承A1的,概率各50%。继承A0的话与B相同的概率是P(A0, B),继承A1的话与B相同的概率是P(A1, B)。那么这个基因与B相同的概率就是:

(P(A0, B)+P(A1, B))/2

因此,A的每个基因与B相同的概率都是(P(A0, B)+P(A1, B))/2,具有相同的概率。进而,AB相同基因的数量概率平均也为(P(A0, B)+P(A1, B))/2AB的相似程度 P(A, B)=(P(A0, B)+P(A1, B))/2这样就归纳证明了P(A, B)的概率递推公式。

下面总结一下前面得出的结论: (1)边界条件:① A=B:P(A, B)1;② AB无相同基因:P(A, B)=0

(2)递推关系:

P(A, B)(P(A0, B)+P(A1, B))/2,其中A0A1A的父母

有了边界条件和递推关系,以及Family Tree的阶段性和无后效性作为前提,用动态规划解决问题的所有条件都已满足。应该说,从理论上来讲,本题已经完全解决。下面需要讨论的仅仅是实现方法而已。动态规划的实现方法有两种:一种是逆向的递推,另一种是正向的记忆化搜索(递归)。这两种方法都是可行的,区别仅仅在于,递推需要更多的考虑状态的阶段性,按照阶段计算出所有状态的值;而记忆化搜索只需要承认状态具有阶段性,无需考虑阶段,只需要按照递推式本身设计带记忆化的递归函数即可。本题给出的仅仅是一棵Family Tree,并没有给出Family Tree的阶段,如果要用递推的话,就必须先给Family Tree分阶段(拓扑排序)。所以,本题显然更适合用记忆化搜索来实现。

另外,需要注意的是,本题所求的答案是有多少精度就输出多少精度。300个节点的图,少说也可以构成几十层的Family Tree,算出的结果至少也有小数点后几十位。所以,高精度是必不可少的(保险起见,可以设置300位的高精度)。

分析一下本题的时间复杂度。动态规划的状态有n2个,转移代价为O(C)(高精度计算的代价)。因此,时间复杂度为为O(Cn)n≤300

严格的讲,本题的算法不能算动态规划的方法,因为本题不存在最优化,应该仅仅是一个递推。不过,从分析问题的过程来看,它里面包含了很多动态规划的思想,例如,阶段性和无后效性,特别是使用了动态规划的一种实现方法记忆化搜索。

 

 

 

你可能感兴趣的:(NOIP解题报告)