Recycling Bottles CodeForces - 672C (几何,贪心)

大意: 平面三个点A,B,C, 两人在A,B处, 垃圾桶在C处, 有n个瓶子, 求把两人将瓶子全扔进垃圾桶的最短距离和的最小值

考虑每个人的行走路线, 一定是这种形式 |Aa1|+|a1C|+|Ca2|+|a2C|+|Ca3|+|a3C|+...

也就是说除了第一个拿的瓶子外, 其余瓶子贡献都为2|aiC|

所以就得到答案为 $\min\limits_{x!=y}(|Aa_x|-|a_xC|+|Ba_y|-|a_yC|)+2\sum\limits|a_iC|$

这样遍历一下求出$|Aa_x|-|a_xC|$和$|Ba_y|-|a_yC|$最小值即可

复杂度O(n)

#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;

const int N = 4e5+10, INF = 0x3f3f3f3f;
struct Point {
	int x, y;
	Point () {}
	Point (int x, int y) :x(x),y(y) {}
	void rd() {
		scanf("%d%d", &x, &y);
	}
	Point operator - (Point p) {
		return Point(x-p.x,y-p.y);
	}
	double dis() {
		return sqrt(x*x+y*y);
	}
} A, B, C, a[N];

double calc(Point x, int p) {
	return (x-a[p]).dis()-(a[p]-C).dis();
}

int n, s1[N], s2[N];

int main() {
	A.rd(),B.rd(),C.rd();
	scanf("%d", &n);
	double ans = 0;
	REP(i,1,n) { 
		a[i].rd();
		ans += (a[i]-C).dis()*2;
		s1[++*s1] = i;
		PER(i,2,*s1) if (calc(A,s1[i])<calc(A,s1[i-1])) swap(s1[i],s1[i-1]);
		*s1 = min(*s1, 2);
		s2[++*s2] = i;
		PER(i,2,*s2) if (calc(B,s2[i])<calc(B,s2[i-1])) swap(s2[i],s2[i-1]);
		*s2 = min(*s2, 2);
	}
	double mi = 1e20;
	REP(i,1,*s1) REP(j,1,*s2) if (s1[i]!=s2[j]) {
		mi = min(mi, calc(A,s1[i])+calc(B,s2[j]));
	}
	printf("%.12lf\n", ans+mi);
}

猜你喜欢

转载自www.cnblogs.com/uid001/p/10416967.html