第一次个人项目作业
1. 在文章开头给出教学班级和可克隆 的 Github 项目地址(例子如下)。(1')
- 教学班级:005
- 项目地址:https://github.com/github/platform-samples.git
2. 在开始实现程序之前,在下述 PSP 表格记录下你估计将在程序的各个模块的开发上耗费的时间。(0.5')
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | ||
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 20 | 21 |
· Design Spec | · 生成设计文档 | 15 | 16 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 35 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 8 |
· Design | · 具体设计 | 10 | 9 |
· Coding | · 具体编码 | 300 | 320 |
· Code Review | · 代码复审 | 60 | 50 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 100 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | ||
· Size Measurement | · 计算工作量 | ||
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | ||
合计 |
3. 解题思路描述。即刚开始拿到题目后,如何思考,如何找资料的过程。(3')
首先看到基本需求:给定 N 条直线,询问平面中有多少个点在至少 2 条给定的直线上。题目输入保证答案只有有限个。
数据要求:所有直线参数均为整数,范围为 (-100000, 100000)。
代码评分规则:
- 正确性评分 — 20 分。正确性测试中输入的几何对象个数满足 1 <= N <= 1000,要求程序在 60 秒内给出结果,超时则认定运行结果无效。
- 性能评分 — 10 分。性能测试中输入的几何对象个数满足 1000 <= N <= 500000,交点个数 h 满足 0 <= h <= 5000000,要求程序在 60 秒内给出结果。性能评分将采取档级评分制度,助教将根据同学们的程序跑同一数据耗费的时间长度将程序分为若干档,第 n 档的同学得到的分数为 10 / n。注:当程序的正确性评分等于 20 分时才可以参与性能评分环节,所以请各位同学务必保证自己程序的正确性。
分析:
题目的实际需求就是求解多条直线的交点。除了正确性的要求之外,还要尽可能提高性能。那么,首先考虑如何求解:
若已知两条直线方程 \(L_1: y = k_1x + b_1, L_2: y = k_2x + b_2\),且\(k_1 \neq k_2\),可直接联立得到解。
若有一条直线是垂直的,\(L_1: x = x_0, L_2: y = k_2x + b_2\),可带入求解。
若两条直线平行,没有交点。
直线方程的公式有以下几种形式:
斜截式:
\[\begin{equation}y=kx+b\end{equation}\]
截距式:
\[\begin{equation}x/a+y/b=1\end{equation}\]
两点式:
\[\begin{equation}(x-x1)/(x2-x1)=(y-y1)/(y2-y1)\end{equation}\]
一般式:
\[\begin{equation}ax+by+c=0\end{equation}\] (可以表达任意直线)
在这里采用斜截式,只需要建立直线的时候计算\(k, b\)(或垂直\(x\)轴),空间复杂度小,在之后的计算中也非常简洁。
以上为基本求解方法。
那么,如何对所有直线求解呢?
最直观的想法是对所有直线分别求交点,时间复杂度为\(O(n^2)\)。但是,这样粗暴的解法的性能无疑是很低的。在网络上查找资料,想到平行线可以作为一个集合,集合内不用求交点。但是,要求平行线集合仍然要遍历它们的斜率,和直接求交点的时间复杂度并无太大区别,因为在求交点的时候,若斜率相同,那么可以直接跳过。另外,由于存在多条直线交于同一点的情况,实际上对于所有可能的交点,都要求出具体的交点坐标。那么,平行线集合的优势也被进一步削弱了。所以总体上,这一类做法的复杂度都是\(O(n^2)\)。
在这一基础上,可以做一些初步的优化,即已经求过交点的两条直线不再求解。如:有直线\(L_1, L_2\),在求解\(L1\)对\(L_2\)的交点之后,不需要反过来求交点。如此可以节省一半的时间。
其次,在确定算法之后,考虑数据的精度问题。在题目直线参数为(-100000, 100000)的情况下,float精度是达不到要求的。只有使用double才能满足精度约束。