poj 1127 Jack Straws 挑戰程序設計競賽
地址 http://poj.org/problem?id=1127

解法
使用ccw 如果兩個線段相交,對于其中一個線段的兩個點,另外一個線段的兩個點分別是處于逆時針方向和順時針方向的
也就是說 線段1的ab兩點 分別和線段2的cd兩點計算叉積 應該是正負不同的。
相交的所有線段算作同一組,這里使用并查集合并。
代碼如下
#include <iostream>
#include <cmath>
using namespace std;
const double PI = 2.0 * acos(0.0);
struct vector2 {
double x, y;
explicit vector2(double x_ = 0, double y_ = 0) :x(x_), y(y_) {}
bool operator ==(const vector2& rhs)const {
return x == rhs.x && y == rhs.y;
}
bool operator <(const vector2& rhs)const {
return x != rhs.x ? x < rhs.x : y < rhs.y;
}
vector2 operator+(const vector2& rhs)const {
return vector2(x + rhs.x, y + rhs.y);
}
vector2 operator-(const vector2& rhs)const {
return vector2(x - rhs.x, y - rhs.y);
}
vector2 operator*(double rhs)const {
return vector2(x * rhs, y * rhs);
}
double norm()const {
return hypot(x, y);
}
//單位向量
vector2 normalize()const {
return vector2(x / norm(), y / norm());
}
//從x軸的正方向 逆時針旋轉到達當前向量時候的角度
double polar()const { return fmod(atan2(y, x) + 2 * PI, 2 * PI); }
//點積
double dot(const vector2& rhs)const {
return x * rhs.x + y * rhs.y;
}
//叉積
double cross(const vector2& rhs)const {
return x * rhs.y - rhs.x * y;
}
//將當前向量映射到rhs的結果
vector2 project(const vector2& rhs)const {
vector2 r = rhs.normalize();
return r * r.dot(*this);
}
};
double ccw(vector2 a, vector2 b) {
return a.cross(b);
}
double ccw(vector2 p, vector2 a, vector2 b) {
return ccw(a - p, b - p);
}
//返回兩個線段是否相交
bool segmentIntersects(vector2 a, vector2 b, vector2 c, vector2 d) {
double ab = ccw(c, a, b) * ccw(d, a, b);
double cd = ccw(a,c, d) * ccw(b,c, d);
//兩條線段在同一直線上或端點相互重疊時
if (ab == 0 && cd == 0) {
if (b < a) swap(a, b);
if (d < c) swap(c, d);
return !(b < c || d < a);
}
return ab <= 0 && cd <= 0;
}
struct line {
vector2 l, r;
};
const int N = 15;
struct line LI[N];
int f[N];
int n;
void init() {
for (int i = 0; i < N; i++) { f[i] = i; }
}
int find(int x) {
if (f[x] != x) f[x]= find(f[x]);
return f[x];
}
void merge(int a,int b) {
a = find(a); b = find(b);
f[a] = b;
}
/*
7
1 6 3 3
4 6 4 9
4 5 6 7
1 4 3 5
3 5 5 5
5 2 6 3
5 4 7 2
1 4
1 6
3 3
6 7
2 3
1 3
0 0
2
0 2 0 0
0 0 0 1
1 1
2 2
1 2
0 0
0
*/
void solve() {
//先測試所有線段是否相交 記錄并查集
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (find(i) != find(j)) {
if (segmentIntersects(LI[i].l, LI[i].r, LI[j].l, LI[j].r)) {
merge(i, j);
}
}
}
}
int a, b;
while (cin >> a >> b) {
if (a == 0 && b == 0)break;
if (find(a) == find(b)) {
cout << "CONNECTED" << endl;
}
else {
cout << "NOT CONNECTED" << endl;
}
}
return;
}
int main()
{
while (cin >> n) {
if (0 == n) break;
init();
memset(LI, 0, sizeof LI);
for (int i = 1; i <= n; i++) {
cin >> LI[i].l.x >> LI[i].l.y >> LI[i].r.x >> LI[i].r.y;
}
solve();
}
return 0;
}
作 者: itdef
歡迎轉帖 請保持文本完整并注明出處
技術博客 http://www.rzrgm.cn/itdef/
B站算法視頻題解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
歡迎c c++ 算法愛好者 windows驅動愛好者 服務器程序員溝通交流
如果覺得不錯,歡迎點贊,你的鼓勵就是我的動力
歡迎轉帖 請保持文本完整并注明出處
技術博客 http://www.rzrgm.cn/itdef/
B站算法視頻題解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
歡迎c c++ 算法愛好者 windows驅動愛好者 服務器程序員溝通交流
如果覺得不錯,歡迎點贊,你的鼓勵就是我的動力
浙公網安備 33010602011771號