当前位置: 首页 > news >正文

计算几何初步:CCW 与判断两线段的相交性

本文写于 2025 年 9 月 18 日。

前言

昨天在正睿的“IOI 普及联赛”中,有这样一道题,极大地冲击了本蒟蒻的心灵。赛后查看题解,此题竟然涉及计算几何,这更是本蒟蒻从未涉足的领域。我遂查询资料,学习了 CCW 算法以及用其判断线段是否相交的方法,并迅速写了一个骗得 25 分的代码。借此机会,我想分享一下 CCW 算法及利用其判断两线段是否相交的方法。

CCW 算法

CCW 是 Counter-Clockwise 的缩写,即逆时针方向。顾名思义,此算法用来计算两首尾相接的向量的转向关系。

CCW 的本质是向量叉积。给定两个向量,\(\vec{AB}\)\(\vec{AC}\),它们的向量叉积公式为 \(cross = \vec{AB} \times \vec{AC} = (B_x - A_x) (C_y - A_y) - (B_y - A_y) (C_x - A_x)\),这个 \(cross\) 就是判断转向的依据:

  • \(cross < 0\) 时,从点 \(A\) 到点 \(B\) 再到点 \(C\),路径呈逆时针方向旋转。
  • \(cross = 0\) 时,\(A, B, C\) 三点共线
  • \(cross < 0\) 时,从点 \(A\) 到点 \(B\) 再到点 \(C\),路径呈顺时针方向旋转。

C++ 代码实现参考:

struct Point {double x, y;
};double ccw(Point a, Point b, Point c) {return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}

判断两线段是否相交

众所周知,对于两条线段 \(AB\)\(CD\),如果 \(A\)\(B\) 分别在 \(CD\) 的两侧,且 如果 \(C\)\(D\) 分别在 \(AB\) 的两侧,则 \(AB\)\(CD\) 相交。前者需满足 \(\mathrm{ccw}(A, B, C) \times \mathrm{ccw}(A, B, D) < 0\),即从向量 \(\vec{AB}\) 转向点 \(C\) 与点 \(D\) 的方向相反;类似地,后者需满足 \(\mathrm{ccw}(C, D, A) \times \mathrm{ccw}(C, D, B) < 0\)

C++ 代码实现参考(需结合以上 ccw 的函数定义):

if (ccw(a, b, c) * ccw(a, b, d) < 0 && ccw(c, d, a) * ccw(c, d, b) < 0) {// 两条线段相交
}

相关题目参考题解

题目大意:给出 \(N\) 个点,两两连接这些点组成一个线段集合 \(S\),求 \(S\) 中不与其它任何线段相交的线段数量。

注意:以下题解是暴力做法,只能在原题中获得 25 分,AC 做法请参考官方题解。

#include <iostream>
#include <vector>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e3 + 10;
struct Point {int x, y;
} p[N];
struct Side {Point a, b;
};
vector<Side> s;
int n, ans;
int ccw(Point a, Point b, Point c) {return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);
}signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n; i++) {int x, y;cin >> x >> y;p[i] = {x, y};}for (int i = 1; i <= n - 1; i++) {for (int j = i + 1; j <= n; j++) {s.push_back({p[i], p[j]});}}for (int i = 0; i < s.size(); i++) {int suc = true;for (int j = 0; j < s.size(); j++) {Point a = s[i].a, b = s[i].b, c = s[j].a, d = s[j].b;if (ccw(a, b, c) * ccw(a, b, d) < 0 && ccw(c, d, a) * ccw(c, d, b) < 0) {suc = false;break;}}if (suc) {ans++;}}cout << ans << endl;return 0;
}

小结

CCW 算法只是计算几何庞大世界的沧海一粟,这一广阔的算法天地仍有很多地方值得我们探索。例如,若要在上文提到的题目中获得满分,必须要学习包括凸包在内的更高级的计算几何算法。路漫漫其修远兮,希望大家以十足的兴趣,自主探索计算几何的奇妙世界。

http://icebutterfly214.com/news/422/

相关文章:

  • 20251027周一日记
  • 学校协同云盘怎么选?2025年10大热门教育网盘推荐与对比
  • GPU集群之间的交互
  • CF1267G Game Relics
  • 102302115方朴第一次作业
  • 解题报告-梦熊 CSP-S2025 模拟赛T2
  • 鄙“站”麻将和算24,刷新后会换
  • 20232422 2025-2026-1 《网络与系统攻防技术》实验三实验报告
  • 20232404 2025-2026-1 《网络与系统攻防技术》实验三实验报告
  • 「WC2014-紫荆花之恋」题解
  • 谢谢你周医生
  • 来源未知
  • Date 10.27
  • 10.27及动手动脑
  • go包装bing搜索
  • 鼾声识别芯片方案和睡眠产品的应用场景
  • 2025年工程管理软件公司综合推荐榜:助力建筑行业数字化升级
  • Excel高性能异步导出完整方案!
  • 2025年多功能综合杆厂家排名前十推荐
  • 2025年度在线网站客服系统综合排行榜正式发布
  • JDD Oxygen智能零售论坛 | 《大模型时代的广告营销变革与实践》
  • 2025年市面上新加坡留学品牌、行业内公司及口碑产品推荐排行
  • 11-文件上传
  • TensorFlow与PyTorch深度对比分析:从基础原理到实战选择的完整指南 - 指南
  • Navicat 17 超详细保姆级下载安装教程:附激活工具使用步骤​
  • el-date-picker样式修改
  • 浅谈 Agent 开发工具链演进历程
  • 电梯调度算法结对编程作业
  • 2025质量可靠的义乌刺绣工厂推荐榜
  • DP1312多协议高性能读卡芯片支持A/B/Felaca/18092智能门锁读卡器模拟卡兼容PN512 - 动能世纪