- 1、本文档共3页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
〖问题2〗乘船问题——信息学NOI联赛辅导专题.doc
〖〗
NOI竞赛辅导 王建德教练讲稿
有N个人需要乘船,而每船最多只能载两人,且必须同名或同姓。求最少需要多少条船。
两点间用实线表示同姓,虚线表示同名
【】m个结点的二叉树Tm,需要船的数量(Tm对应的连通分量的覆盖边数)为boat[m]=[m/2](m(N)。
证明:
当m=1,m=2,m=3时命题显然成立。
假设当mk(k3)时命题成立,那么当m=k时,我们首先从树中找到一个层次最深的结点k,并假设这个结点的父亲为p,即(p,k)为非桥边。那么,此时有且只有以下三种情况(结点中带有阴影的是p结点):
如图(a),p只有一个儿子。此时删去p和p唯一的儿子,Tk就成为了Tk-2,则boat[k]=boat[k-2]+1=[(k-2)/2]+1=[k/2]。
如图(b),p有两个儿子,并且p是其父亲的左儿子。此时可删去p和p的右儿子,并可将p的左儿子放到p的位置上。同样地,Tk成为了Tk-2,boat[k]=boat[k-2]+1=[k/2]。
如图(c),p有两个儿子,并且p是其父亲的右儿子。此时可删去p和p的左儿子,并可将p的右儿子放到p的位置上。情况与(2)十分相似,易得此时得boat[k]=boat[k-2]+1=[k/2]。
综合(1)、(2)、(3),当m=k时,boat[k]=[k/2]。
最后,综合(i)、(ii),对于一切m(N,boat[m]=[m/2]。
proc try(father:integer;var root:integer;var rest:byte);{输出root为树根的子树的乘船方案,father=0表示root是其父亲的左儿子;father=1表示root是其父亲的右儿子,rest表示输出子树的乘船方案后,是否还剩下一个根结点未乘船}
visit[root]:=true; {标记root已访问}
找到一个与root同姓且未访问的结点j;
if jn+1 then try(0,j,lrest);
找到一个与root同名且未访问的结点k;
if kn+1 then try(1,k,rrest);
if (lrest=1) xor (rrest=1) {判断root是否只有一个儿子,情况一}
then if lrest=1 then输出lrest和root同乘一条船
else 输出rrest和root同乘一条船;
rest:=0;
else if (lrest=1) and (rrest=1) {判断root是否有两个儿子}
then if father=0
then 输出rrest和root同乘一条船;
root:=j; {情况二}
else 输出lrest和root同乘一条船;
root:=k; {情况三}
rest:=1;
else rest:=1;
for j:=1 to n
do if not visit[j] {若有一个人未访问,则证明其处在另一棵子树中}
then i:=j;
try(1,i,rest);{以这个未访问的点为根结点建立子树,并输出该子树中所有人的乘船方案}
if rest=1 {最后是否还剩下一个人}
then 输出i乘一条船;
inc(total);
输出船的总数total;
文档评论(0)