训练3.22(C: Recyling Bottles)

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);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值