题意:
告诉你a和b两人的坐标和垃圾桶t的坐标,两人捡垃圾,有n个垃圾,分别给出坐标。每次只能捡一项,每次捡到垃圾后需上交到垃圾桶处,之后可选择继续捡垃圾或休息。
垃圾必须捡完,问你捡完所有垃圾,a和b两人走的最小路程是多长。
分析:
对于a和b,当两人第1次捡过垃圾之后,必定会回到垃圾桶交垃圾,之后所有捡第2个到第n个垃圾的路程为:垃圾到垃圾桶的路程*2,因为都只能从垃圾桶出发,到垃圾坐标捡取,再回到垃圾桶。
那么a和b的初始位置决定了第1次捡垃圾时应选取哪一个垃圾作为捡取对象。实际上可将所有垃圾到垃圾桶的路程*2,并求和为sum。而a和b第一次捡垃圾时路程应为:人到垃圾的路程+垃圾到垃圾桶的路程。假设a将捡取第k个垃圾,那么总路程sum应加上(a到垃圾k的路程-垃圾k到垃圾桶的路程),即为当前最短路程,即相当于此时a节约了总路程,节约量为:(a到垃圾k的路程-垃圾k到垃圾桶的路程)。
那么确定a和b分别捡哪个垃圾,即可得出最终答案。
问题在于a、b捡垃圾的状态。由于(a到垃圾k的路程-垃圾k到垃圾桶的路程)不一定小于0,即有可能a到垃圾k的距离比垃圾桶到k还远,还不如让b捡完垃圾以后从垃圾桶出发捡取垃圾k,因此a和b的状态需要讨论。
设a捡取垃圾k时能使总路程最短。
当a节约的路程(a到垃圾k的路程-垃圾k到垃圾桶的路程)< 0时,对总路程有帮助,此时让a捡取k即可。
当(a到垃圾k的路程-垃圾k到垃圾桶的路程)> 0时,那么a休息即可,因为此时a继续捡取垃圾无法缩短路程,应让b继续捡取。
b同理分析,但存在特殊情况。
1.a和b均休息时,此时必须让a或b继续捡垃圾,虽然此时两人捡垃圾都只能令sum增大,但只能选取相对令sum增大较小的人捡。
2.a和b选择了相同垃圾捡取,只需计算出a能使总路程最短的垃圾ak1与次短ak2,与相应的bk1与bk2。此时ak1=bk1,那么令a选择ak2或者b选择bk2,比较哪种能令路程更短,则选择哪种。
莫名其妙写了这么长,感觉之前题解写的太简略了,这次写长一些……
不知道是不是这场cf人太少,为什么这题过的人这么少……昨晚要是熬夜就能涨分了……可惜……
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <fstream>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const int N=100005;
const int mod=1e9+7;
struct poi{
int x,y;
}g[N],a,b,t;
double dis(poi x,poi y) {
double temp=0;
temp=(double)(x.x-y.x)*(x.x-y.x)+(double)(x.y-y.y)*(x.y-y.y);
temp=sqrt(temp);
return temp;
}
int main() {
int n;
while (cin>>a.x>>a.y>>b.x>>b.y>>t.x>>t.y) {
cin>>n;
double am,bm,ax,bx;
am=bm=0;
ax=bx=1e20;
double sum=0;
for (int i=1; i<=n; i++) {
scanf("%d %d",&g[i].x,&g[i].y);
sum+=2*dis(g[i], t);
}
int flaga,flagb;
double fa,fb;
flaga=flagb=0;
for (int i=1; i<=n; i++) {
fa=dis(g[i], a)-dis(g[i], t);
fb=dis(g[i], b)-dis(g[i], t);
if (fa<am) {
ax=am;
am=fa;
flaga=i;
} else if (fa<ax) {
ax=fa;
}
if (fb<bm) {
bx=bm;
bm=fb;
flagb=i;
} else if (fb<bx) {
bx=fb;
}
}
double temp=0;
if (flaga!=0&&flagb!=0) {
if (flaga==flagb) {
temp=min(ax+bm, am+bx);
} else temp=am+bm;
} else if (flagb>0||flaga>0) {
if (flaga>0) temp+=am;
if (flagb>0) temp+=bm;
} else {
temp+=min(ax, bx);
}
sum+=temp;
printf("%.12lf\n",sum);
}
return 0;
}