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;
}

我的视频题解空间

posted on 2023-02-10 15:53  itdef  阅读(15)  评论(0编辑  收藏  举报

导航