题意

给定一个由 $n$ 个点组成的凸包, $q$ 次询问,每次询问给出一个圆,求出从凸包到圆各处最小期望长度。

$n,q\leq5000$

题解

如果圆心在凸包里直接从圆心出发,否则看圆心到凸包的距离。

代码

const int N = 5010;
const ld eps = 1e-6;

inline ll read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, q;
	int sgn(ld x) {
		if (x < -eps) return -1;
		if (x >  eps) return 1;
		return 0;
	}
	typedef complex<ld> vec;
	ld dot(vec a, vec b) { return real(a) * real(b) + imag(a) * imag(b); }
	ld cross(vec a, vec b) { return real(a) * imag(b) - imag(a) * real(b); }
	
	vec a[N];
	bool inhull(vec p) {
		for (int i = 0; i < n; ++i)
			if (sgn(cross(a[i] - p, a[(i + 1) % n] - p)) <= 0) return 0;
		return 1;
	}
	ld dis(vec p, vec a, vec b) {
		if (abs(b - a) > eps && sgn(dot(p - a, b - a)) >= 0 && sgn(dot(p - b, a - b)) >= 0)
			return fabs(cross(p - a, b - a)) / abs(b - a);
		return min(abs(p - a), abs(p - b));
	}
	int main () {
		n = read(), q = read();
		for (int i = 0; i < n; ++i) {
			int x = read(), y = read();
			a[i] = vec(x, y);
		}
		while (q--) {
			int x = read(), y = read(); vec A = vec(x, y);
			x = read(), y = read(); vec B = vec(x, y);
			vec O = (A + B) / (ld)2.0;
			ld r = abs(O - A), d = 1e18;
			if (inhull(O)) d = 0;
			else {
				for (int i = 0; i < n; ++i)
					d = min(d, dis(O, a[i], a[(i + 1) % n]));
			}
			printf ("%.9Lf\n", ((long double) r * r / 2 + (long double) d * d));
		}
		return 0;
	}
}

int main () {
	string str = "";
//	freopen((str + ".in").c_str(), "r", stdin);
//	freopen((str + ".out").c_str(), "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2025-08-30 14:35:51
博客类型