BUAA-OO-U3-Summary
BUAA-OO-U3-Summary
1 问题描述
本单元的主要任务是根据JML
描述来实现一个人际关系管理网络。
该网络有三个层面,person
,group
以及network
。首先,network
是最顶层的结构,所有的人都属于这一个网络,主要处理人与人之间的关系网络;group
就像是群聊,可以容纳部分(或全部)人,但group
之间并没有互斥性,就像是同一个人可以加入不同的群聊一样,主要处理年龄、消息和“社交能量”的统计;person
就是一个个体,存储了这个人与哪些人有关以及收到的消息等。
2 总体架构
本单元在架构上的自主性不强,主要通过完成JML
的描述来进行。其中,三次作业对JML
描述的实现上有以下几个重点:
作业 | 问题 | 解决 |
---|---|---|
hw9 | qci (两个人是否在同一个连通块中)与qbs (查新连通块的数量) |
新建一个union 类,通过路径压缩 + 按秩合并优化的并查集解决 |
hw10 | qlc (查询个人所在的连通块的最小生成树) |
利用kruskal 算法计算单次答案,利用并查集父节点保存和更新答案 |
hw11 | sim (求连通块中两点间的最短路径) |
利用Dijkstra 算法计算答案 |
具体实现如下:
//并查集
public class MyUnion {
private final HashMap<Integer, Integer> fa;
private final HashMap<Integer, Integer> size;
public MyUnion() {
fa = new HashMap<>();
size = new HashMap<>();
}
public void add(int id) {
fa.put(id, id);
size.put(id, 1);
}
public int getfa(int id) {
if (fa.get(id) == id) {
return id;
}
int father = getfa(fa.get(id));
fa.put(id, father);
return father;
}
public void merge(int id1, int id2) {
int fa1 = getfa(id1);
int fa2 = getfa(id2);
if (fa1 == fa2) {
return;
}
if (size.get(fa1) > size.get(fa2)) {
int fa = fa1;
fa1 = fa2;
fa2 = fa;
}
fa.put(fa1, fa2);
size.merge(fa2, size.get(fa1), Integer::sum);
}
}
//qlc update (kruskal)
private void update(int id) {
MyUnion u = new MyUnion();
int sum = 0;
int cnt = 0;
PriorityQueue<Integer> edges =
new PriorityQueue<>(Comparator.comparingInt(this::edgeValue));
for (MyPerson p : people.values()) {
if (union.getfa(p.getId()) == union.getfa(id)) {
u.add(p.getId());
++cnt;
}
}
for (int i = 0; i < edgeCnt; i++) {
int x = edgeX.get(i);
if (union.getfa(x) == union.getfa(id)) {
edges.add(i);
}
}
while (!edges.isEmpty() && cnt > 1) {
int i = edges.poll();
int x = edgeX.get(i);
int y = edgeY.get(i);
if (union.getfa(x) == union.getfa(id) &&
union.getfa(y) == union.getfa(id) &&
u.getfa(x) != u.getfa(y)) {
u.merge(x, y);
sum += edgeValue(i);
--cnt;
}
}
minConnection.put(union.getfa(id), sum);
updated.put(union.getfa(id), true);
}
//dijkstra
private int getDis(int st, int ed) {
HashMap<Integer, Integer> dis = new HashMap<>();
PriorityQueue<MyPoint> queue = new PriorityQueue<>();
queue.add(new MyPoint(st, 0));
dis.put(st, 0);
while (!queue.isEmpty()) {
MyPoint point = queue.poll();
if (point.getDis() != dis.get(point.getId())) {
continue;
}
MyPerson x = people.get(point.getId());
for (Person p : x.getAcquaintance().values()) {
if (dis.get(p.getId()) == null ||
dis.get(p.getId()) > point.getDis() + x.queryValue(p)) {
dis.put(p.getId(), point.getDis() + x.queryValue(p));
queue.add(new MyPoint(p.getId(), point.getDis() + x.queryValue(p)));
}
}
}
return dis.get(ed);
}
3 互测总结
本次实验在互测中的限制较大,难以通过性能进行hack,因此hack成功率不高;
同时,作为一个被公开的“1111”,受到了房间中多人X多次的hack,总的来说是一次惨痛的失败经历。
4 个人总结
本次实验相对来说是一次比较简单的实验,由于JML
描述对操作的接口和影响进行了限制,在完成单个函数的过程中几乎不需要考虑过多,一般通过查找新增功能涉及的函数
->设计新功能
->依次实现各个函数
三个步骤即可,也令我感受到了规格化设计对实现的巨大简化效果。