HDU6697 Closest Pair of Segments(几何数学)

HDU6697 Closest Pair of Segments(几何数学)


来源:

HDU6697 Closest Pair of Segments


题意:

给出 n 条线段, 每个线段给出两个端点, 求任意两条线段的最短距离中最短的一个距离


代码:

#include <bits/stdc++.h>
#define endl "\n"
#define rep(i, m, n) for (int i = (m); i <= (n); ++i)
#define rrep(i, m, n) for (int i = (m); i >= (n); --i)
#define IOS ios::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 10, mod = 1e9 + 7;
int n, x[N];
struct point {
	double x, y;
	point operator-(const point& a) const { 
		return { x - a.x, y - a.y }; 
	}
	bool operator>(const point& a) const {
		if (x == a.x) return y > a.y;
		return x > a.x;
	}
	bool operator<(const point& a) const {
		if (x == a.x) return y < a.y;
		return x < a.x;
	}
	bool operator==(const point& a) const {
		return x == a.x && y == a.y;
	}
};
struct line { point bg, ed; }s[N];
const double eps = 1e-8;
int sign(double x) { // 判断符号
	if (fabs(x) < eps) return 0;
	if (x < 0) return -1;
	return 1;
}
double dot(point a, point b) { return a.x * b.x + a.y * b.y; } // 点乘
double cross(point a, point b) { return a.x * b.y - b.x * a.y; } // 叉乘
double get_length(point a) { return sqrt(dot(a, a)); } // 边长
double distance_to_line(point p, point a, point b) { // 点到直线的距离
	point v1 = b - a, v2 = p - a;
	return fabs(cross(v1, v2) / get_length(v1));
}
double distance_to_segment(point p, point a, point b) { // 点到线段的距离
	if (a == b) return get_length(p - a);
	point v1 = b - a, v2 = p - a, v3 = p - b;
	if (sign(dot(v1, v2)) < 0) return get_length(v2);
	if (sign(dot(v1, v3)) > 0) return get_length(v3);
	return distance_to_line(p, a, b);
}
double distance_segment_segment(line a, line b) { // 线段到线段的距离
	double x = distance_to_segment(a.bg, b.bg, b.ed);
	double y = distance_to_segment(a.ed, b.bg, b.ed);
	double z = distance_to_segment(b.bg, a.bg, a.ed);
	double q = distance_to_segment(b.ed, a.bg, a.ed);
	if (x > y) x = y;
	if (x > z) x = z;
	if (x > q) x = q;
	return x;
}
bool cmp(line a, line b) { return a.bg < b.bg; }
void solve() {
	scanf("%d", &n);
	rep(i, 1, n) {
		scanf("%lf %lf %lf %lf", &s[i].bg.x, &s[i].bg.y, &s[i].ed.x, &s[i].ed.y);
		if (s[i].bg > s[i].ed) swap(s[i].bg, s[i].ed);
	}

	sort(s + 1, s + 1 + n, cmp);

	double ans = 2e15;
	rep(i, 1, n) rep(j, i + 1, n) {
		if (sign(s[j].bg.x - s[i].ed.x - ans) >= 0) break; // 剪枝
		double res = distance_segment_segment(s[i], s[j]);
		if (res < ans) ans = res;
	}
	printf("%.12f\n", ans);
}
int main() {
	int t; cin >> t;
	while (t--) solve();
	return 0;
}

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值