题意:
有N个墓碑,等距离的分布在一个圆形墓地的周围,然后又要添加m个墓碑,最后要求所有的墓碑还是等距离,添加的墓碑可以放在任意位置,问之前的N个墓碑的最少移动距离之和是多少?
此题代码是我摘得书上的,分析是摘自以为博主的,接上博主的链接:
(http://blog.csdn.net/u013761036/article/details/41350385)
思路:
现在我们猜想,如果之前的n个墓碑至少有一个是不动的,那么来了m个墓碑之后的所有墓碑的位置都已经固定了,现在就是看要把之前的n个墓碑都放在哪个位置,现在有一个结论就是说每个墓碑放在离他最近的位置,这样就ok了,这么敲有两个东西要证明
(1) 为什么至少有一个墓碑是没有移动的(这个我还没想好,书上说是之前的例3的中位数,那个我理解了,不过这个我没想好怎么和他们联系上,以后再补充.)
(2) 每个墓碑移动到最近的位置是不是会有两个墓碑最后移动到同一个位置的时候?
这个我来证明下:
方法1 给的n,m都是<= 1000的,我们直接跑一边验证一下就行了。
方法2 是直接证明,首先对于每个墓碑去它最近的位置可以这样算
比如第i个墓碑那么我们现在先在单位原上操作,最后*10000就行了
pos = double(i) / n * (n + m) ://这个其实是把圆放大后i原来的实际位置
tmp = abs(pos - int(pos+0.5))/(n + m):// int(pos+0.5)是放大后i的实际位置
如果有两个点的最近点在同一个点上那么就会有int(pos1+0.5) = int(pos2+0.5)
也就是两个数的四舍五入值相等,那么这两个数的最大差是1.49999..-0.5虽然很接 近1,但是永远都不可能是1,而放大的圆的每两个点之间的距离都是1,随意矛盾了
最后解释下上面说的那个放大 就是之前是把一个单位圆分成n分,现在是把一个周长为(n+m)的圆分成(n+m)分,每份是1,放大后离自己最近的点就是离自己最近的整数点也就是四舍五入后的点。
代码:
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
int main(void){
int m,n;
while(cin>>m>>n){
double ans=0.0;
for(int i=1;i<m;i++){
double pos=(double)i/m*(m+n);
ans+=fabs(pos-floor(pos+0.5))/(m+n);
}
cout<<setiosflags(ios::fixed)<<setprecision(4)<<ans*10000<<endl;
}
return 0;
}