BUAA北航OO第三单元总结
作者:互联网
OO第三单元总结
第三单元的内容主要是契约式编程,根据官方给定的JML进行代码的编写。由于JML给出了每个方法的前置条件、后置条件、副作用,实现难度和前两个单元比起来可谓是低了很多,但规格是规格,实现是实现,如果实现完全按照官方JML来写一定是不行的,否则很容易TLE(比如第十次作业的qgvs)
架构设计
UML类图
HW9
HW10
HW11
可以看出都是课程组给好的架构,只是为了维护连通块建立了一个Disjoint类维护并查集
架构设计
本单元作业是模拟一个社交网络,通过阅读JML我们可以知道每个person是社交网络图中的一个点,而person之间的relation则是图中的边,而person类中的acquaintance属性则是一个点与之连通的点,Network中的addRelation指令则是在两个person之间添加两条有向边,people属性则是图结构的邻接表
由此可见,JML已经帮我们描绘了一个天然的带权无向图,因此图结构不需要特别维护,用到图结构的时候我们只需要使用JML要求我们维护的people邻接表即可。
算法技巧
1.并查集
qci指令要求我们频繁查询图中两个点的连通性,而并查集天生就是为了这种要求而存在的,只需要在ap中为并查集添加节点、ar中维护并查集连通性,即可实现qci的O(1)查询
但是仁慈的课程组并没有要求我们实现删除两个人之间的关系的指令,否则原版并查集将无法使用。我在做作业时曾搜索了一些资料,发现也不是不行,只是需要维护一个虚源点,但如果出题出到这份上似乎就违背OO的本意了,所以我觉得往后的OO第三单元也不会出现这条指令。。。
但值得注意的是,并查集有按秩合并和路径压缩(启发式合并)两种写法(两者也可以一起用,但路径压缩会破坏按秩合并的规则性),其中路径压缩的递归写法可以构造数据爆栈,即图结构退化成链结构时。比如这样的数据
ap 1 1 200
ap 2 2 200
ap 3 3 200
ap 4 4 200
.....
ap 5000 5000 200
ar 1 2 1000
ar 2 3 1000
ar 3 4 1000
ar 4 5 1000
ar 5 6 1000
ar 6 7 1000
ar 7 8 1000
......
ar 4999 5000 1000
qci 1 5000
但需要1w条指令才能爆栈,而互测的指令数被限制为5000条(否则想必又是一场腥风血雨)
2.堆优化的prim算法(最小生成树)
第十次作业要求我们实现qlc指令,即给出从一个点出发的最小生成树,最小生成树的算法有prim和克鲁斯卡尔
其中注意到我们的作业加一个点需要一条指令ap,加一条边需要在加点的基础上再加边,平均下来需要指令数更多,因此我们作业的图一般情况下是稀疏图,而稀疏图使用克鲁斯卡尔比较好,有O(mlog(m))的复杂度
但我最终选用的是堆优化的prim算法,O(mlog(n))复杂度,一方面是考虑到其与克鲁斯卡尔复杂度差不多,并不会超时;另一方面是考虑到使用克鲁斯卡尔还需要额外多建立一个类,再维护边的信息,比较麻烦
堆优化的prim只需要采用java自带的PriorityQueue以及使用new int[]{node, dist}在qlc的方法中维护到每个点的最短路,并不需要建立额外的类,比较方便
实现重点:前面说到JML已经帮我们维护了一个天然的邻接表存储的图形结构(这也是堆优化的prim算法容易实现的一个原因:邻接表存储),我们只需要从给定的id开始,对当前id的person(点)的熟人列表(边)进行遍历,将满足条件的熟人的id加入到堆中即可,无需维护额外的数据结构
3.堆优化的迪杰斯特拉算法(最短路)
第十一次作业的sim指令要求我们将查询两个person之间的最短路,最短路的算法有很多(迪杰斯特拉、floyd、spfa、Bellman等),我选择其中性能较好(spfa已死)又比较容易实现的堆优化的迪杰斯特拉算法,复杂度为O(nlog(n))
由于堆优化的prim算法和堆优化的迪杰斯特拉极为相似(这也是最小生成树使用堆优化prim的好处之一
标签:OO,0.3,random,BUAA,北航,指令,JML,choice,生成 来源: https://www.cnblogs.com/sdjasj/p/16329256.html