题目链接:http://codeforces.com/contest/336/problem/B
1、这道题是纯数学题,找下规律后发现答案就是下层每个点到上层每个点的连线的长度之和。刚开始想用暴力法,用了一个m*m的二重循环,理所当然地TLE了,因为重复计算次数太多了,比如水平距离为2的两个圆的最短距离“总和”就是(2*r+2*根号2*r)+(2*r+根号2*r)+(2*r),不用每次都重复算(重复相加),只要保存到数组s里就可以了。所有点算完后将得到的总和ans乘以二,再减去重复的部分即可。当然我的算法稍有区别,不是最后减去多余的,而是一开始就不算2*r的部分,到最后再加上2*m*r。具体见代码。
#include<cstdio> #include<cmath> using namespace std; double ans; int m,r,i; double a[100010],s[100010]; int main(){ while(scanf("%d%d",&m,&r)==2){ ans=0.0; a[0]=0.0; a[1]=2*r+sqrt(2)*r; a[2]=2*r+2*sqrt(2)*r; for(int i=3;i<m;i++) a[i]=a[i-1]+2*r; s[0]=a[0]; for(int i=1; i<m; i++){ s[i]=s[i-1]+a[i]; } for(int i=1;i<=m;i++) ans+=s[m-i]; ans*=2; ans+=2*m*r; ans/=(double)m; ans/=(double)m; printf("%.10lf\n",ans); } return 0; }