OO-Unit3
OO第三单元——JML 一. 单元架构设计 相比于前两单元需要自行设计架构,充当架构设计师的角色,U3不需要设计架构,需要完成的任务是依据课程组给出的架构设计合理的类协作关系以及依据JML写对应的代码(码农日常)。 关于课程组给出的架构可以简单概括如下图 二. 算法实现与性能 本单元更加关注的是对于既定的JML或者说给定的功能要求,具体的算法实现和效率。强测中对于性能有一定要求,性能不佳会爆CTLE。我的理解中,CTLE字面意思上是CPU时间超时,换句话说其实就是**“算的次数太多“**,在本单元作业中,可以采用缓存一些计算复杂度较高的结果进行优化等,下面基于每一次作业进行分析。 1. hw9 这一次作业中主要的性能考察点是关于query_block_sum中查询两个点是否联通的功能。在本次作业中,通过addRelation和modifyRelation可以建立起一个社交图,这其中需要注意的是modifyRelation操作可能删边。很多大佬同学实现了可以删边的并查集,我选择了实现较为简单(懒)的BFS。使用BFS进行联通查询面对大量查询指令有CTLE风险,故可以考虑对BFS进行一点简单优化,例如使用双向BFS。关于双向BFS,其实就是从起点和终点同时开始搜索,面对图中点非常多的情况可以大幅减少开销。 下面是一张摘自广度优先搜索之双向bfs(实操篇)-CSDN博客的一张很形象的图片。 双向BFS的优势其实就是大幅减少搜索宽度,减少遍历一些点,让它看上去没有那么暴力。由此还有一种优化的思路就是均衡取节点。当我们从给起点和终点分别设置的队列中取节点时,可以选择从size较小的那一个队列中取出(size较大的那一方说明他每一层中的宽度较大,遍历开销大)。下面给出我的具体实现(主要想法是起点终点两个队列两个visited数组,当前遍历如果另一边如果遍历过,结束): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import java.util.HashMap; import java.util.LinkedList; import java.util.Queue; public class BreadthFirstSearch { public static boolean isConnected(MyPerson person1,MyPerson person2) { if (person1.getId() == person2.getId()) { return true; } HashMap<Integer, Boolean> visited1 = new HashMap<>(); HashMap<Integer, Boolean> visited2 = new HashMap<>(); visited1.put(person1.getId(),true); visited2.put(person2.getId(),true); Queue<MyPerson> queue1 = new LinkedList<>(); Queue<MyPerson> queue2 = new LinkedList<>(); queue1.add(person1); queue2.add(person2); while (!queue1.isEmpty() && !queue2.isEmpty()) { if (queue1.size() < queue2.size()) { MyPerson now = queue1.poll(); if (next(now,visited1,visited2,queue1)) { return true; } } else { MyPerson now = queue2.poll(); if (next(now,visited2,visited1,queue2)) { return true; } } } return false; } private static boolean next(MyPerson now,HashMap<Integer,Boolean> visited, HashMap<Integer,Boolean> visited2,Queue<MyPerson> queue) { for (Person next : now.getAcquaintance().values()) { if (visited.containsKey(next.getId())) { continue; } if (visited2.containsKey(next.getId())) { return true; } queue.add((MyPerson) next); visited.put(next.getId(),true); } return false; } } 对于另一个查询指令query_triple_sum也需要进行动态维护,在addRelation加边和modifyRelation删边时进行判断,并更新qts的值。 ...