- 1、本文档共7页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 5、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 6、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 7、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 8、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
《食物链》解题报告
《食物链》解题报告
广东北江中学 方奇
问题描述 见Noi2001全国信息学奥赛第一试第一题
问题抽象
如何判断两个动物之间的关系,是解决本题的关键。对应于图论模型,将每个动物看成一个点,并将在输入数据中出现的有直接联系的每对动物之间连一条边。那么,任两个动物之间存在联系,当且仅当对应的两个点处在同一连同分支中。若将互相有联系的动物归于一个集合,那么本题实际上是一个典型的并查集问题。
问题分析
并查集的实现,利用树这种数据结构,无论时空上都是最优的。
结合本题,描述如下:
一棵树对应于一群相互间确定了关系的动物,树的一个结点对应于一个动物。Father[I]记录了结点I的父亲,当I为根结点时,有Father[I]=0。Kind[I]记录了结点I与父亲的相对关系:1表示I被Father[I]吃;2表示I吃Father[I];0表示I与Father[I]是同类。当I为根结点时,有Kind[I]=0。
算法开始时,Father[I]=0,Kind[I]=0,表示先建立n棵不同的树。
容易设计出算法的流程
简单
判断后 Y N
Y
N
下面来看看关键步骤如何实现。
利用Father,不断上溯,分别找出x、y所属树的根结点Rootx、Rooty。则x、y处在同一棵树中,当且仅当Rootx=Rooty。例如:
Rootx=x;
While father[rootx]0 do
rootx:=father[rootx];
在中添加运算,得到x、y分别与根的关系d1、d2
Rootx:=x;d1:=0;
While father[rootx]0 do
Begin
D1:=(d1+kind[rootx]) mod 3;
Rootx:=father[rootx];
End;
从而得到x、y之间的关系d3=(d1+3-d2) mod 3
与相同,先求出d1、d2,在结合x与y之间的关系d,确定出rootx、rooty之间的关系d4=(d1+(d-1)-d2+3) mod 3。合并时只需修改Father[rooty]=rootx、Kind[rooty]=d4即可。
可以看出、本身的耗时都为O(1),但它们都要借助与的结果。当树退化成一条链时,每次耗时将达到O(n)。于是有必要进行改进。
改进一
设num[root]记录以root为根的树的结点数(不含根),每次合并时总将“小树”合并到“大树”中。随着小树T1合并到大树T2中,T1的每个结点深度增加1,且合并后的T2的结点数至少是T1的结点数的2倍。于是,并查集中的每个结点至多被移动O(logN)次,从而每个结点所在树的高度不会超过O(logN)。所以每次只需O(logN)时间。
改进二
采用路径压缩技术。即在每次执行的过程中,记录下上溯的路径,将路上所有结点的父亲(Father)
经过上述改进后,算法的时间复杂度大大减少,基本上可以认为是O(N+K)。
程序注释
Program Eat;
var father,kind,num,l1,l2:array[1..50000] of longint;
i,j,k,n,m,x,y,z,k1,k2,t1,t2,tot:longint;
root1,root2:longint;
f1,f2:text;
procedure init;
{初始化文件}
begin
assign(f1,eat.in);
reset(f1);
assign(f2,eat.out);
rewrite(f2);
readln(f1,n,m);
end;
procedure main;
{主过程}
procedure Findroot;
{上溯出结点的根}
begin
t1:=0;root1:=x;k1:=0;
while root10 do
begin
inc(t1);
l1[t1]:=root1;
k1:=(k1+kind[root1]) mod 3;
root1:=father[root1];
end;
root1:=l1[t1];
{root1为x的根,k1为x与根的关系}
t2:=0;root2:=y;k2:=0;
while root20 do
begin
inc(t2);
l2[t2]:=root2
文档评论(0)