2021-面向对象设计与构造-第三单元总结

第九次作业

架构与设计策略

架构上,完全照搬给出的接口,对于每一个接口 (或异常抽象类) A 创建了 MyA 将其实现 (或继承)。

三次作业都是这么做的,因此不在后两次作业中进行赘述了。

绝大部分方法只需复制规格,异常类的实现使用 static 成员变量记录每个 id 的出现次数即可。

三次作业异常类大致相同,因此不在后两次作业中进行赘述了。

无向图中添加点、添加边、查询任意两点间是否连通、查询连通块数量,可以使用路径压缩+启发式合并的并查集,单次操作 \(O(\alpha(n))\) 或 \(O(1)\) 的复杂度内完成。

因为 idint 范围内且强制在线,需要使用 HashMap 存储,时间上还要乘以一个小常数,不过问题不大。

查询 name 的排名直接复制规格进行暴力,单次复杂度不超过 \(O(|s|n)\),其中 \(|s|\) 是串长。写平衡树可以优化到 \(O(|s| \log n)\),但这么小数据范围根本没必要。

测试与 bug 分析

因为功能过于简单,主要采用随机生成数据和室友对拍的方法。同时构造了一些极端数据防止算法写假。

强测与互测中没有出现 bug,互测中主要采取看代码+构造的方法 hack 了 \(3\) 个人,hack 内容见下面的性能分析。

容器选择

MyNetwork 中使用 HashMap 存储每个 Person,以及并查集中的 fa 数组与 siz 数组,键均为 id

MyPerson 中使用 HashMap 存储边的权值,键为 id

异常类中使用 HashMap 存储每个 id 的出现次数,键为 id

性能分析

我的实现中,复杂度瓶颈在于查询 name 的排名。

此外,查询连通块数量的 JML 规格是以 \(O(n^2)\) 次调用 isCircle 方法给出的,如果直接照搬规格, isCircle 的实现又比较慢,就可以被卡成 TLE,互测中也是根据这个问题进行 hack。

第十次作业

架构与设计策略

架构上,完全照搬给出的接口,对于每一个接口 (或异常抽象类) A 创建了 MyA 将其实现 (或继承)。

对于 GroupvalueSum,每次新增 Person 或删除 Person 时维护改变量,单次修改复杂度 \(O(n)\),单次查询复杂度 \(O(1)\)。

对于 GroupageMeanageVar,通过维护 age 的和与平方和可以做到单次 \(O(1)\) 询问与修改,但是这并不是复杂度瓶颈,索性直接 \(O(n)\) 暴力。

剩下的方法就没有什么优化余地了,直接照搬规格即可。

需要注意的是以下两个坑:

  • valueSum 是有序的,每条边的权值要算两次。
  • 一个人可能在好几个组里,addRelation 时要考虑将对应边的权值加到对应的 Group 中。

测试与 bug 分析

因为功能过于简单,主要采用随机生成数据和室友对拍的方法。同时构造了一些极端数据防止算法写假。

强测与互测中没有出现 bug,互测中主要采取看代码+构造的方法 hack 了 \(2\) 个人,hack 内容见下面的性能分析。

组内另有一人使用了 ArrayList 而非 HashMap,看代码时完全忽略,没有针对其进行构造,错失了这个机会。

容器选择

MyNetwork 中使用 HashMap 存储每个 GroupMessage,键值为对应 id

MyPerson 中使用 ArrayList 存储他收到的信息。

MyGroup 中使用 HashMap 存储其中的 Person,键值为 id

性能分析

Group 中查询 valueSumJML 规格是以 \(O(n^2)\) 次调用 isLinked 方法给出的,如果直接照搬规格,可以被卡成 \(O(n^3)\) 从而造成 TLE,互测中也是根据这个问题进行 hack。

第十一次作业

架构与设计策略

架构上,完全照搬给出的接口,对于每一个接口 (或异常抽象类) A 创建了 MyA 将其实现 (或继承)。

除了最短路,其它部分的规格都是单纯模拟,没有优化余地。

对于无负边权的单源最短路,使用优先队列实现的堆优化 Dijkstra 算法可以在 \(O(m \log m)\) 的复杂度内完成。

测试与 bug 分析

因为功能过于简单,主要采用随机生成数据和室友对拍的方法。同时构造了一些极端数据防止算法写假。

强测与互测中没有出现 bug,互测中主要采取看代码+构造的方法进行 hack,但大家写的都很对,因此没有 hack 成功。

容器选择

MyNetwork 中使用 HashMap 实现规格中的 emojiHeatList

MyNetwork 中利用 PriorityQueue 实现了堆优化 Dijkstra 算法。

性能分析

在本题的数据范围和 \(6\) 秒时限下,单次最短路询问 \(O(m \log m)\) 是可以通过的。

不过,需要注意 Dijkstra 的暴力算法并非毫无用途,其复杂度为 \(O(n^2)\),在稠密图上快于堆优化,例如这个题 CF1528D

总结与收获

  1. 感谢课程组为我们减负,三次作业简直是从头暴力到尾,老爽了。当然,一个缺点就是写博客不知道写啥,理论课上老师说要我们多写点儿,但是我觉得真的没啥好写的,如果助教审阅时觉得字数太少我可以再水一些(逃

  2. Java8 的 HashMap 非常人性化,当一个哈希值的元素过多时会将链表转化为红黑树,元素过少时又会将红黑树转化为链表,降低了哈希冲突的代价,也让我断绝了我卡哈希的想法

  3. 理论课上老师多次提出:「形式化方法工程应用受限。」

    这三次作业让我深刻体会到了这一点。一些方法寥寥几行就能写完,形式化规格却要写的特别臃肿冗长。如果说这么做的代价是能进行形式化验证,那么意味着可以做到严格意义上的无 bug,简直再好不过了。但是现实是还需要自己造数据进行测试,那「形式化」就会成为效率的阻碍。

    希望以后能看到形式化验证在工程上广泛应用的那一天,这样就再也不用担心没找出来的 bug 了

上一篇:2021红帽杯 web find_it


下一篇:OO_Unit3