[P3493 WSP-Island] 题解

[P3493 WSP-Island] 题解

来水一篇题解

显然路径 A 1 → A → B → A 6 A_1\to A\to B\to A_6 A1ABA6 最短,可以想到最优路径就是沿着“最内侧”的边走,我们可以使用三角形两边之和大于第三边进行浅浅的证明我就不证了(逃

而我们可以使用半平面交求解“最内侧”多边形,所以很容易想到链接 A 1 A 6 A_1A_6 A1A6 ,这样就形成了一个封闭图形。但是 O ( n 2 ) O(n^2) O(n2) 条边略微有辣么亿点点大,所以我们又发现了对于每个点,“最内侧”的边,一定是与其相连,另一端编号最大的边,所以当加边的时候可以先排一下序。答案就是交平面的周长减去 A 1 A n A_1A_n A1An

贴上代码

namespace geometry {
	double pi = acos(-1);
	struct point {
		double x, y;
		point(double _x = 0, double _y = 0)
			: x(_x), y(_y) {}
		inline void read() {
			cin >> x >> y;
		}
		inline friend double dist(point a, point b) {
			double sq1 = (a.x - b.x), sq2(a.y - b.y);
			return sqrt(sqr(sq1) + sqr(sq2));
		}
		inline friend bool operator==(point a, point b) {
			return a.x == b.x && a.y == b.y;
		}
		inline friend bool operator!=(point a, point b) {
			return a.x != b.x || a.y != b.y;
		}
		inline friend point operator-(point a, point b) {
			return point(a.x - b.x, a.y - b.y);
		}
		inline friend point operator+(point a, point b) {
			return point(a.x + b.x, a.y + b.y);
		}
		inline friend double cross(point a, point b) {
			return a.x * b.y - a.y * b.x;
		}
		inline friend double dot(point a, point b) {
			return a.x * b.x + a.y * b.y;
		}
		inline friend point operator*(point a, double b) {
			return point(a.x * b, a.y * b);
		}
	};
	using line = pair<point, point>;
	double dist_sqr(point a, point b) {
		return sqr(a.x - b.x) + sqr(a.y - b.y);
	}
	inline double len(point p, point l, point r) {
		point x1 = l - p, x2 = r - p;
		return cross(x1, x2) / dist(l, r);
	}
	double c(double x) {
		if (x > 1)
			return 1;
		if (x < -1)
			return -1;
		return x;
	}
	inline double angle(point a, point b, point rt = point()) {
		return acos(c(dot(a - rt, rt - b) / dist(a, rt) / dist(b, rt)));
	}
	inline double check(point a1, point a2, point b1, point b2) {
		return (a2.x - a1.x) * (b2.y - b1.y) - (b2.x - b1.x) * (a2.y - a1.y);
	}
	vector<point> convex_hull(vector<point> p) {
		point g = p[0];
		for (int i = 1; i < p.size(); i++) {
			if (p[i].y < g.y || (p[i].y == g.y && p[i].x < g.x))
				g = p[i];
		}
		sort(p.begin(), p.end(), [&](point a, point b)->bool {
			double sum = cross(a - g, b - g);
			if (sum > 0)
				return true;
			if (sum < 0)
				return false;
			return dist(a, g) < dist(b, g);
			});
		vector<point> res(p.size());
		int cnt = -1;
		res[++cnt] = p[0];
		for (int i = 1; i < p.size(); i++) {
			while (cnt > 0 && check(res[cnt - 1], res[cnt], res[cnt], p[i]) <= 0)
				cnt--;
			res[++cnt] = p[i];
		}
		res.resize(cnt + 1);
		return res;
	}
	double diameter(vector<point> p) {
		int sz = p.size();
		if (sz < 3)
			return dist_sqr(p[0], p[(1) % sz]);
		int j = 2;
		double res = 0;
		p.push_back(p[0]);
		for (int i = 0; i < sz; i++) {
			while (cross(p[i + 1] - p[i], p[(j + 1) % sz] - p[i]) > cross(p[i + 1] - p[i], p[j] - p[i]))
				j = (j + 1) % sz;
			res = max(res, dist_sqr(p[i], p[j]));
		}
		return res;
	}
	point itsect(line a, line b) {
		return a.first + a.second * (cross(b.second, a.first - b.first) / cross(a.second, b.second));
	}
	bool right(line a, point b) {
		return cross(a.second, b - a.first) < EPS;
	}
	vector<point> plane(vector<line> v) {
		sort(v.begin(), v.end(), [&](line a, line b)->bool {
			return atan2(a.second.y, a.second.x) < atan2(b.second.y, b.second.x);
			});
		int l = 0, r = 0;
		vector<point> t(v.size());
		vector<line> q(v.size());
		q[0] = v[0];
		for (int i = 1; i < v.size(); i++) {
			while (l < r && right(v[i], t[r]))
				r--;
			while (l < r && right(v[i], t[l + 1]))
				l++;
			q[++r] = v[i];
			if (abs(cross(q[r].second, q[r - 1].second)) < EPS) {
				if (right(q[r], q[r - 1].first) && dot(q[r].second, q[r - 1].second) < EPS)
					return vector<point>();
				r--;
				if (!right(q[r], v[i].first))
					q[r] = v[i];
			}
			if (l < r)
				t[r] = itsect(q[r], q[r - 1]);
		}
		while (l < r && right(q[l], t[r]))
			r--;
		if (r - l <= 1)
			return vector<point>();
		t[l] = itsect(q[l], q[r]);
		return vector<point>(t.begin() + l, t.begin() + r + 1);
	}
	double area(vector<point> p) {
		if (p.size() <= 2)
			return 0;
		double res = 0;
		for (int i = 0; i < p.size() - 1; i++)
			res += cross(p[i], p[i + 1]);
		res += cross(p.back(), p[0]);
		return res / 2;
	}
	double circumference(vector<point> p) {
		if (p.size() < 2)
			return 0;
		if (p.size() == 2)
			return dist(p[0], p[1]);
		double res = 0;
		for (int i = 0; i < p.size() - 1; i++)
			res += dist(p[i], p[i + 1]);
		res += dist(p.back(), p[0]);
		return res;
	}
	double area(point p1, point p2, point p3) {
		return abs(cross(p1 - p3, p2 - p3)) / 2;
	}
}
using namespace geometry;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n, m; cin >> n >> m;
	vector<point> p(n);
	for (int i = 0; i < n; i++)
		p[i].read();
	vector<line> l;
	vector<vector<int>> dn(n);
	for (int i = 0; i < m; i++) {
		int x, y; cin >> x >> y;
		--x, --y;
		if (x < y)
			swap(x, y);
		dn[x].push_back(y);
	}
	for (int i = 0; i < n; i++)
		sort(dn[i].begin(), dn[i].end());
	for (int i = 0; i < n; i++) {
		int j = 0, k = 0;
		for (j; j < i && k < dn[i].size(); j++, k++)
			if (dn[i][k] != j)
				break;
		if (j != i)
			l.push_back({ p[i], p[j] - p[i] });
	}
	l.push_back({ p.front(), p.back() - p.front() });
	vector<point> pla = plane(l);
	double ans = circumference(pla) - dist(p.front(), p.back());
	printf("%.5llf\n", ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值