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.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力

