Jackiesteed

www.github.com/jackiesteed

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

首先,考虑简单情况,两个人的距离太近,就要走远一点,那么两个人可以同时向相反方向走,那么要走距离X花费时间为X/2,而当一个人静止,

另一个人移动,这样两个人远离X要花费时间X,是前一种情况的2倍,这样就可以进行一下转化,即两人相互远离时只需要移动一个人.结果减半

即可.

以上可以推广到N个人, 人的位置任意的情况,即N个人要相互拉开距离,就是固定一个人fixed,其他人都以相邻的靠近fixed的人为参照

进行移动,结果除以2即可.

解题思路陈述:

(1)任意相邻两人的距离都在D范围内:

固定最左的vendor,然后向右迭代,每一个人距其左邻X,右邻就要相对于左邻向右移D-X距离,因为每个人都是相对于其左邻移动,而不受其他人的

影响,所以每一人向右移动所需的时间的和是总共球的时间.

(2),任意相邻两人距离在D范围内,或是INF:

当中间有相邻两个人相距为INF时,左邻无论需要向右移动多远,都不会影响右邻,则右邻不需要向右移动,这时前后就被分割成了互相独立的

组了,组与组之间的成员移动互不影响,对于每组球出一个结果,用最大值来更新最终的结果即可.

(3)相邻两人距离可以取任意值:

这比(2)中多了一种D<X<INF的情况,这时X左邻由于受到其左边的人右移的影响,可能会移动到距右邻小于D的位置,甚至超过右邻,此时如果

仍然套用(2)的思路,就要在每次遇到一个D<X时,维护一个acc积累值,表示左面一组向右移动对右面造成的影响,右面一组需要首先通通向右

移动acc距离,再进行本组的操作,这样就可以使用(2)中方法解题.

附源代码:

View Code
#include <iostream>
#include
<algorithm>
#include
<cstring>
#include
<climits>
#include
<cstdio>
#include
<cmath>
#include
<cstring>

using namespace std;

int P[1000],V[1000];
int array[1100000];
int C,D;

int main()
{
freopen(
"B-large.in","r",stdin);
freopen(
"output.out","w",stdout);

int T;
scanf(
"%d",&T);

for(int loop=1;loop<=T;loop++)
{
scanf(
"%d%d",&C,&D);

for(int i=0;i<C;i++)
{
scanf(
"%d%d",&P[i],&V[i]);
}

int cnt=0;
//下面循环将vendor按坐标序写入数组
for(int i=0;i<C;i++)
{
while(V[i])
{
array[cnt
++]=P[i];
V[i]
--;
}
}
double tmp=0;//记录每组的结果
double res=0;//记录最终结果
int start=0;
double acc=0;//acc记录左面一组对右面一组的影响
for(int i=1;i<cnt;i++)
{
if(D>array[i]-array[i-1]) //距离小于D时
{
tmp
+=double(D-array[i]+array[i-1]);//累加到本组的结果中
}
else //距离大于等于D时,
{
if(res<tmp+acc) //用最大值更新res
res=tmp+acc;
tmp
=0;

//修改acc,如果左面一组会对右面一组产生影响
if(double(array[i]-array[start])<acc+double(i-start)*double(D))
{
acc
=acc+double(i-start)*double(D)-double(array[i]-array[start]);
}
else//没有影响则acc=0
{
acc
=0;
}
start
=i;
}
}
if(res<tmp+acc)
res
=tmp+acc;
res
/=2;
printf(
"Case #%d: %0.10lf\n",loop,res);

}

return 0;
}
posted on 2011-05-22 05:46  Jackiesteed  阅读(171)  评论(0编辑  收藏  举报