pascal教程6树.docx

上传人:b****4 文档编号:4103107 上传时间:2023-05-06 格式:DOCX 页数:19 大小:77.53KB
下载 相关 举报
pascal教程6树.docx_第1页
第1页 / 共19页
pascal教程6树.docx_第2页
第2页 / 共19页
pascal教程6树.docx_第3页
第3页 / 共19页
pascal教程6树.docx_第4页
第4页 / 共19页
pascal教程6树.docx_第5页
第5页 / 共19页
pascal教程6树.docx_第6页
第6页 / 共19页
pascal教程6树.docx_第7页
第7页 / 共19页
pascal教程6树.docx_第8页
第8页 / 共19页
pascal教程6树.docx_第9页
第9页 / 共19页
pascal教程6树.docx_第10页
第10页 / 共19页
pascal教程6树.docx_第11页
第11页 / 共19页
pascal教程6树.docx_第12页
第12页 / 共19页
pascal教程6树.docx_第13页
第13页 / 共19页
pascal教程6树.docx_第14页
第14页 / 共19页
pascal教程6树.docx_第15页
第15页 / 共19页
pascal教程6树.docx_第16页
第16页 / 共19页
pascal教程6树.docx_第17页
第17页 / 共19页
pascal教程6树.docx_第18页
第18页 / 共19页
pascal教程6树.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

pascal教程6树.docx

《pascal教程6树.docx》由会员分享,可在线阅读,更多相关《pascal教程6树.docx(19页珍藏版)》请在冰点文库上搜索。

pascal教程6树.docx

pascal教程6树

第六章树

 

6.1排序二叉树

源程序名tree.?

?

?

(pas,c,cpp)

可执行文件名tree.exe

输入文件名tree.in

输出文件名tree.out

【问题描述】

一个边长为n的正三角形可以被划分成若干个小的边长为1的正三角形,称为单位三

角形。

如右图,边长为3的正三角形被分成三层共9个小的正三角形,我们把它们从顶到

底,从左到右以1~9编号,见右图。

同理,边长为n的正三角形可以划分成n2个单位三

角形。

四个这样的边长为n的正三角形可以组成一个三棱锥。

我们将正三棱锥的三个侧面依

顺时针次序(从顶向底视角)编号为A,B,C,底面编号为D。

侧面的A,B,C号三角形以

三棱锥的顶点为顶,底面的D号三角形以它与A,B三角形的交点为顶。

左图为三棱锥展

开后的平面图,每个面上标有圆点的是该面的顶,该图中侧面A,B,C分别向纸内方向折

叠即可还原成三棱锥。

我们把这A,B、C、D四个面各自划分成n2个单位三角形。

对于任意两个单位三角形,如有一条边相邻,则称它们为相邻的单位三角形。

显然,每个单位三角形有三个相邻的单位三角形。

现在,把1—4n2分别随机填入四个面总共4n2个单位三角形中。

现在要求你编程求由单位三角形组成的最大排序二叉树。

所谓最大排序二叉树,是指在所有由单位三角形组成的排序二叉树中节点最多的一棵树.对于任一单位三角形,可选它三个相邻的单位三角形中任意一个作为父节点,其余两个分别作为左孩子和右孩子。

当然,做根节点的单位三角形不需要父节点,而左孩子和右孩于对于二叉树中的任意节点来说并不是都必须的。

【输入】

输入文件为tree.in。

其中第一行是一个整数n(1<=n<=18),随后的4n2个数,依次为三棱锥四个面上所填的数字。

【输出】

输出文件为tree.out。

其中仅包含一个整数,表示最大的排序二又树所含的节点数目。

【样例】

输入文件对应下图:

ABCD

tree.intree.out

32213917

1925151

33202628

3221187

3112172

292486

3231636

53427

43511

301410

输出样例文件对应的最大排序二叉树如下图所示:

【知识准备】

记忆化搜索的基本概念和实现方法。

【算法分析】

在讨论问题的解法之前,我们先来看看二叉排序树的性质。

二叉排序树是一棵满足下列性质的二又树:

性质1它或是一棵空树,或是一棵二叉树,满足左子树的所有结点的值都小于根结点的值,右子树的所有结点的值都大于根结点的值;

性质2它若有子树,则它的子树也是二叉排序树。

根据性质1,我们可以知道,二叉排序树的左右子树是互不交叉的。

也就是说,如果确定了根结点,那么我们就可以将余下的结点分成两个集合,其中一个集合的元素可能在左子树上,另一集合的元素可能在右子树上,而没有一个结点同时可以属于两个集合。

这一条性质,满足了无后效性的要求,正因为二叉排序树的左右子树是互不交叉的,所以如果确定根结点后,求得的左子树,对求右子树是毫无影响的。

因此,如果要使排序树尽可能大,就必须满足左右子树各自都是最大的,即局部最优满足全局最优。

根据性质2,二叉排序树的左右子树也是二叉排序树。

而前面已经分析得到,左右子树也必须是极大的。

所以,求子树的过程也是一个求极大二叉排序树的过程,是原问题的一个子问题。

那么,求二叉排序树的过程就可以分成若干个阶段来执行,每个阶段就是求一棵极大的二叉排序子树。

由此,我们看到,本题中,二叉排序树满足阶段性(性质2)和无后效性(性质1),可以用动态规划解决。

下面来看具体解决问题的方法。

不用说,首先必须对给出的正三棱锥建图,建成一张普通的无向图。

根据正三棱锥中结点的性质,每个结点均与三个结点相连。

而根据二叉排序树的性质,当一个结点成为另一个结点的子结点后,它属于左子树还是右子树也就确定下来了。

所以,可以对每个结点进行状态分离,分离出三种状态——该结点作为与它相连的三个结点的子结点时,所得的子树的状态。

但是,一个子结点可以根据它的父结点知道的仅仅是该子树的一个界(左子树为上界,右子树为下界),还有一个界不确定,所以还需对分离出来的状态再进行状态分离,每个状态代表以一个值为界(上界或下界)时的子树状态。

整个分离过程如下图所示:

确定了状态后,我们要做的事就是推出状态转移方程。

前面已经提到,一个极大的二叉排序树,它的左右子树也必须是极大的。

因此,如果我们确定以结点n为根结点,设所有可以作为它左子结点的集合为N1,所有可以作为它右子结点的集合为N2,则以n为根结点、结点大小在区间[l,r]上的最大二叉排序树的结点个数为:

我们所要求的最大的二叉排序树的结点个数为:

,其中n为结点的总个数

从转移方程来看,我们定义的状态是三维的。

那么,时间复杂度理应为O(n3)。

其实并非如此。

每个结点的状态虽然包含下界和上界,但是不论是左子结点还是右子结点,它的一个界取决于它的父结点,也就是一个界可用它所属的父结点来表示,真正需要分离的只有一维状态,要计算的也只有一维。

因此,本题时间复杂度是O(n2)(更准确的说应该是O(3n2))。

此外,由于本题呈现一个无向图结构,如果用递推形式来实现动态规划,不免带来很大的麻烦。

因为无向图的阶段性是很不明显的,尽管我们从树结构中分出了阶段。

不过,实现动态规划的方式不仅仅是递推,还可以使用搜索形式——记忆化搜索。

用记忆化搜索来实现本题的动态规划可以大大降低编程复杂度。

6.2树的重量

源程序名weight.?

?

?

(pas,c,cpp)

可执行文件名weight.exe

输入文件名weight.in

输出文件名weight.out

【问题描述】

树可以用来表示物种之间的进化关系。

一棵“进化树”是一个带边权的树,其叶节点表示一个物种,两个叶节点之间的距离表示两个物种的差异。

现在,一个重要的问题是,根据物种之间的距离,重构相应的“进化树”。

令N={1..n},用一个N上的矩阵M来定义树T。

其中,矩阵M满足:

对于任意的i,j,k,有M[i,j]+M[j,k]<=M[i,k]。

树T满足:

1.叶节点属于集合N;

2.边权均为非负整数;

3.dT(i,j)=M[i,j],其中dT(i,j)表示树上i到j的最短路径长度。

如下图,矩阵M描述了一棵树。

树的重量是指树上所有边权之和。

对于任意给出的合法矩阵M,它所能表示树的重量是惟一确定的,不可能找到两棵不同重量的树,它们都符合矩阵M。

你的任务就是,根据给出的矩阵M,计算M所表示树的重量。

下图是上面给出的矩阵M所能表示的一棵树,这棵树的总重量为15。

【输入】

输入数据包含若干组数据。

每组数据的第一行是一个整数n(2

其后n-l行,给出的是矩阵M的一个上三角(不包含对角线),矩阵中所有元素是不超过100的非负整数。

输入数据保证合法。

输入数据以n=0结尾。

【输出】

对于每组输入,输出一行,一个整数,表示树的重量。

【样例】

weight.inweight.out

515

5912871

8117

51

4

4

153660

3155

36

0

【知识准备】

树的基本特征。

【算法分析】

本题是一道涉及树性质的算法题,所以我们应该以树的性质为突破口,来讨论本题的算法。

首先来看一下简单的实例,就以题目中给出的例子来说明。

下图所示的树,有5个叶子节点,两个内点,6条边。

我们已知的信息是任意两个叶子节点之间的距离,所以我们讨论的必然是叶子节点之间的关系,不可能涉及内点。

从图中我们可以看出,有些叶子结点是连在同一个内点上的,如①和②;也有些连在不同的内点上,如①和④。

我们来看连在同一内点上的叶子节点有什么特殊的性质。

就以①和②为例,①到③、④、⑤的距离分别为9、12、8,②到③、④、⑤的距离分别为8、11、7,正好都相差l。

这个“1”差在哪里呢?

①连到内点的边长为3,②连到内点的边长为2,两者相差为1。

所以,相差的“1”正好就是两节点连到内点上的边长的差。

再看①到②的距离,由于两叶子节点都是连在同一个内点上的,所以他们之间的距离,就是两者到内点的边长和。

知道的边长和以及边长差,求出两边长就不难做到了。

(注意:

两叶子节点连到内点的边长是未知的)

再看一下不连在同一内点上的节点,①和④。

①到②、③、⑤的距离分别为5、9、8,④到②、③、⑤的距离分别为11、5、4,没有一个统一的“差”。

其实,前面的结论都是非常直观而显然的,只不过关键是如何去利用。

我们先来总结一下前面的结论:

(1)如果两叶子节点连在同一个内点上,则它们到其他叶子节点的距离有一个统一的“差”;

(2)如果两叶子节点连在不同的内点上,则它们到其他叶子节点的距离没有一个统一的“差”;

/

○────●────●

a\

值得注意的是,图6-3中的a点不能算内点。

我们所指的内点是至少连接两个叶子节点的点,像a这样的点完全可以去掉,不会影响树的权值和,如下图。

/

○─────────●

\

(3)如果两叶子节点连在同一个内点上,则它们之间的距离等于它们各自到内点的边长的和。

根据

(1)和

(2)两条性质,很容易得到判断连接相同内点的两个叶子节点的方法,即必须满足它们到其他所有叶子节点有统一的距离差(充分且必要)。

找到两个连接相同内点的叶子节点并计算出它们各自到内点的边长(不妨设为l1和l2)以后,我们可以作这样的操作:

删去一个节点,令另一个节点到内点的边长为l1+l2。

这样得到的新树,权值和与原树相同,但叶子节点少了一个,如下图。

反复利用上述操作,最后会得到一棵只有两个叶子节点的树,这两个节点之间的边长就是原树的权值和。

算法需要反复执行n-2次删除节点的操作。

每次操作中,需要枚举两个叶子节点,并且还要有一个一维的判断,时间复杂度是O(n3)的。

所以,整个算法的时间复杂度是O(n4)的。

对于一个规模仅有30的题目来说,O(n4)的算法足以解决问题了。

当然,算法本身应该还是有改进的余地的,不过这里就不加以讨论了。

6.3信号放大器

源程序名booster.?

?

?

(pas,c,cpp)

可执行文件名booster.exe

输入文件名booster.in

输出文件名booster.out

【问题描述】

树型网络是最节省材料的网络。

所谓树型网络,是指一个无环的连通网络,网络中任意两个结点间有且仅有一条通信道路。

网络中有一个结点是服务器,负责将信号直接或间接地发送到各终端机。

如图6-4,server结点发出一个信号给结点a和c,a再转发给b。

如此,整个网络都收到这个信号了。

serverab

●────○────○

但是,实际操作中,信号从一个结点发到另一个结点,会出现信号强度的衰减。

衰减量一般由线路长度决定。

server3a2b

●────○────○

│1

如上图,边上所标的数字为边的衰减量。

假设从server出发一个强度为4个单位的信号,发到结点a后强度衰减为4-3=1个单位。

结点a再将其转发给结点b。

由于信号强度为1,衰减量为2,因此信号无法发送到b。

一个解决这一问题的方法是,安装信号放大器。

信号放大器的作用是将强度大于零的信号还原成初始强度(从服务器出发时的强度)。

上图中,若在结点a处安装一个信号放大器,则强度为4的信号发到a处,即被放大至4。

这样,信号就可以被发送的网络中的任意一个节点了。

为了简化问题,我们假定每个结点只处理一次信号,当它第二次收到某个信号时,就忽略此信号。

你的任务是根据给出的树型网络,计算出最少需要安装的信号放大器数量。

【输入】

第一行一个整数n,表示网络中结点的数量。

(n<=100000)

第2~n+1行,每行描述一个节点的连接关系。

其中第i+1行,描述的是结点i的连接关系:

首先一个整数k,表示与结点i相连的结点的数量。

此后2k个数,每两个描述一个与结点i相连的结点,分别表示结点的编号(编号在1~n之间)和该结点与结点i之间的边的信号衰减量。

结点1表示服务器。

最后一行,一个整数,表示从服务器上出发信号的强度。

【输出】

一个整数,表示要使信号能够传遍整个网络,需要安装的最少的信号放大器数量。

如果不论如何安装信号放大器,都无法使信号传遍整个网络,则输出“Nosolution.”

【样例】

booster.inbooster.out

41

22331

21342

111

122

4

【问题分析】

用贪心算法求解。

从叶结点往根结点回推,当信号强度不够继续传送时,即增加一个信号放大器。

算法的时间复杂度为O(n)。

6.4“访问”术馆

源程序名gallery.?

?

?

(pas,c,cpp)

可执行文件名gallery.exe

输入文件名gallery.in

输出文件名gallery.out

【问题描述】

经过数月的精心准备,PeerBrelstet,一个出了名的盗画者,准备开始他的下一个行动。

艺术馆的结构,每条走廊要么分叉为两条走廊,要么通向一个展览室。

Peer知道每个展室里藏画的数量,并且他精确测量了通过每条走廊的时间。

由于经验老到,他拿下一幅画需要5秒的时间。

你的任务是编一个程序,计算在警察赶来之前,他最多能偷到多少幅画。

【输入】

第1行是警察赶到的时间,以s为单位。

第2行描述了艺术馆的结构,是一串非负整数,成对地出现:

每一对的第一个数是走过一条走廊的时间,第2个数是它末端的藏画数量;如果第2个数是0,那么说明这条走廊分叉为两条另外的走廊。

数据按照深度优先的次序给出,请看样例。

一个展室最多有20幅画。

通过每个走廊的时间不超过20s。

艺术馆最多有100个展室。

警察赶到的时间在10min以内。

【输出】

输出偷到的画的数量。

【样例】

gallery.in(如图6-6)gallery.out

602

70803114210012462

【问题分析】

用树型动态规划求解。

首先,题目保证数是二叉树。

定义状态f(n,t)表示在结点n所在子树上花t时间所能取到的最大分值,则状态转移方程为

f(n,t)=max{f(left,t0)+f(right,t-t0)}

其中left和right为n的左右子结点,t0的取值范围为[0,t]。

算法的时间复杂度为O(n3)。

6.5聚会的快乐

源程序名party.?

?

?

(pas,c,cpp)

可执行文件名party.exe

输入文件名party.in

输出文件名party.out

【问题描述】

你要组织一个由你公司的人参加的聚会。

你希望聚会非常愉快,尽可能多地找些有趣的热闹。

但是劝你不要同时邀请某个人和他的上司,因为这可能带来争吵。

给定N个人(姓名,他幽默的系数,以及他上司的名字),编程找到能使幽默系数和最大的若干个人。

【输入】

第一行一个整数N(N<100)。

接下来有N行,每一行描述一个人的信息,信息之间用空格隔开。

姓名是长度不超过20的字符串,幽默系数是在0到100之间的整数。

【输出】

所邀请的人最大的幽默系数和。

【样例】

party.inparty.out

58

BART1HOMER

HOMER2MONTGOMERY

MONTGOMERY1NOBODY

LISA3HOMER

SMITHERS4MONTGOMERY

【问题分析】

用动态规划求解。

首先,很显然公司的人员关系构成了一棵树。

设f[a]为a参加会议的情况下,以他为根的子树取得的最大幽默值;g[a]为a不参加会议的情况下,以他为根的子树取得的最大幽默值。

那么,状态转移方程就是:

f[a]=g[b1]+g[b2]+…+g[bk]+1

g[a]=max(f[b1],g[b1])+max(f[b2],g[b2])+…+max(f[bk],g[bk])

其中b1,b2,…,bk为a的子结点。

最后的答案就是max(f[root],g[root]),root是树根。

6.6重建道路

源程序名roads.?

?

?

(pas,c,cpp)

可执行文件名roads.exe

输入文件名roads.in

输出文件名roads.out

【问题描述】

一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场。

由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。

因此,牧场运输系统可以被构建成一棵树。

John想要知道另一次地震会造成多严重的破坏。

有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目。

【输入】

第1行:

2个整数,N和P

第2..N行:

每行2个整数I和J,表示节点I是节点J的父节点。

【输出】

单独一行,包含一旦被破坏将分离出恰含P个节点的子树的道路的最小数目。

【样例】

roads.inroads.out

1162

12

13

14

15

26

27

28

49

410

411

【样例解释】

如果道路1-4和1-5被破坏,含有节点(1,2,3,6,7,8)的子树将被分离出来

【问题分析】

用树型动态规划求解。

定义f(n,m)为在n为根的子树中取m个节点的最小代价,则状态转移方程为:

f(n,m)=min{f(n0,m0)+f(n1,m1)+f(n2,m2)+…+f(nk,mk)}

其中,n0,n1,n2,…,nk为n的k个儿子,m0+m1+m2+…+mk=m,并且定义f(ni,0)=1。

最后的结果为:

min{f(root,p),min{f(n,p)|n≠root}}

6.7有线电视网

源程序名tele.?

?

?

(pas,c,cpp)

可执行文件名tele.exe

输入文件名tele.in

输出文件名tele.out

【问题描述】

某收费有线电视网计划转播一场重要的足球比赛。

他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。

从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。

现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。

写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。

【输入】

输入文件的第一行包含两个用空格隔开的整数N和M,其中2≤N≤3000,1≤M≤N-1,N为整个有线电视网的结点总数,M为用户终端的数量。

第一个转播站即树的根结点编号为1,其他的转播站编号为2到N-M,用户终端编号为N-M+1到N。

接下来的N-M行每行表示—个转播站的数据,第i+1行表示第i个转播站的数据,其格式如下:

KA1C1A2C2…AkCk

K表示该转播站下接K个结点(转播站或用户),每个结点对应一对整数A与C,A表示结点编号,C表示从当前转播站传输信号到结点A的费用。

最后一行依次表示所有用户为观看比赛而准备支付的钱数。

【输出】

输出文件仅一行,包含一个整数,表示上述问题所要求的最大用户数。

【样例】

tele.intele.out

532

22253

23243

342

【样例解释】

如右图所示,共有五个结点。

结点①为根结点,即现场直播站,②为一

个中转站,③④⑤为用户端,共M个,编号从N-M+1到N,他们为观看比

赛分别准备的钱数为3、4、2,从结点①可以传送信号到结点②,费用为2,

也可以传送信号到结点⑤,费用为3(第二行数据所示),从结点②可以传输信号到结点③,费用为2。

也可传输信号到结点④,费用为3(第三行数据所示),如果要让所有用户(③④⑤)都能看上比赛,则信号传输的总费用为:

2+3+2+3=10,大于用户愿意支付的总费用3+4+2=9,有线电视网就亏本了,而只让③④两个用户看比赛就不亏本了。

【问题分析】

用动态规划求解。

状态这样定义,设F[A,M]为A结点下支持M个用户所能得到的最大赢利。

转移方程为:

F[A,M]=Max{F[B1,M1]+F[B2,M2]+…+F[Bk,Mk]|Bi是A的子结点,M1+M2+…+Mk=M}

可以考虑将多叉数转换成二叉树来做,也可以考虑动态地分配内存。

这样,空间复杂度约为O(n),时间复杂度为O(n2)。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2