cf 671A
题目:http://codeforces.com/problemset/problem/671/A
题意:有A,B两人在捡瓶子。共有n个瓶子,回收箱只有一个,记作 t 。给出A,B,n个瓶子以及回收箱t的坐标位置,求捡完所有垃圾后两人所走过的最短路程。
且,捡瓶子有一定规则:要么不捡,要么直接走直线去捡,捡了之后也必须走直线直接去回收箱。
题解:假设人从决定去捡瓶子k开始到把瓶子k送到回收箱这一段距离称为瓶子k的路径长度,那么画一下图知道,若A捡起了他的第一个瓶子i,那么这个瓶子的路径长度就是dist(t,i)+dist(i,A)。若不曾被A或B捡起的,路径长度为dist(t,i)+dist(i,t)。
dist(i,t)表示i和t的距离。
所以,在n各瓶子中,最多就两个瓶子能被捡起,最少就只有一个瓶子(我才不会说我wa了nnnnnn次就是因为没注意这个)
因为没有瓶子被捡起就等同于A,B两个人都没有选择任一个瓶子作为自己的第一个,那
AB都不捡,n个瓶子总不能自己长脚了自己送自己去回收。
再次吐槽自己 >.<
理清之后好办事!
具体做法
两个结构体数组d1,d2:
d1[i]:若A第一次就取该瓶子时,将多走的距离d1[i].d。
很明显,d1[i].d要选的当然时数值越小越好。
对d2[i]意义如上,只不过是换成B第一次取该瓶子。
同时记录若A,B都不选第一个捡取的瓶子时,应走的距离总长,记作ans。
如此之后,对两个结构体数组排序,升序,这样后数组第一个元素就是A,B两个人各自第一次拾取某个瓶子时,会比原来多走的距离的最小值。
最后就是注意一下:
(1)A选B不选
(2)A不选B选
(3)A选B选:不可选中同一个瓶子。
最理想情况是各自数组第一个瓶子不一样;
否则就令一位取其第一个,另一位取其第二个瓶子,然后两个答案取min。
!!没有A,B都不选的情况!!
详细请看代码,理解可能更快
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1e5+5;
struct node{
int i;double d;
bool operator <(const node& o)const{
return d<o.d;
}
}d1[maxn],d2[maxn];
int main(){
double x1,x2,y1,y2,t1,t2;
cin>>x1>>y1>>x2>>y2>>t1>>t2;
double ans=0;
int n;
cin>>n;
double xx,yy;
for(int i=1;i<=n;i++){
cin>>xx>>yy;
double tmp=sqrt((xx-t1)*(xx-t1)+(yy-t2)*(yy-t2));//瓶子与回收箱距离
ans+=tmp*2;
double tmp1;
tmp1=sqrt((x1-xx)*(x1-xx)+(y1-yy)*(y1-yy)); //瓶子与A距离
d1[i].d=tmp1-tmp;
tmp1=sqrt((x2-xx)*(x2-xx)+(y2-yy)*(y2-yy));//瓶子与B距离
d2[i].d=tmp1-tmp;
d1[i].i=d2[i].i=i;
}
sort(d1+1,d1+1+n);
sort(d2+1,d2+1+n);
double tmp;
tmp=min(d1[1].d,d2[1].d);
if(n>=2){
if(d1[1].i!=d2[1].i)tmp=min(tmp,d1[1].d+d2[1].d);
tmp=min(tmp,min(d1[1].d+d2[2].d,d1[2].d+d2[1].d));
printf("%.12lf",ans+tmp);
}else{
printf("%.12lf",ans+tmp);
}
}