Atcoder-AtCoderBeginner Contest145 C--AverageLength

C - Average Length


Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 300 points

Problem Statement

There are N

towns in a coordinate plane. Town i is located at coordinates (xi, yi).

The distance between Town i and Town j is \sqrt{(x1-x2)^2+(y1-y2)^2}

.There are N! possible paths to visit all of these towns once. Let the length of a path be the distance covered when we start at the first town in the path, visit the second, third, …, towns, and arrive at the last town (assume that we travel in a straight line from a town to another). Compute the average length of these N!

paths.

Constraints

  • 2≤N≤8
  • −1000≤xi≤1000
  • −1000≤yi≤1000
  • (xi,yi)≠(xj,yj)
  • (if i≠j)
  • (Added 21:12 JST) All values in input are integers.

    Input

    Input is given from Standard Input in the following format:

    N
    x1 y1
    :
    xN yN

    Output

    Print the average length of the paths. Your output will be judges as correct when the absolute difference from the judge's output is at most 10^{-6}

     


    Sample Input 1

    3
    0 0
    1 0
    0 1
    

    Sample Output 1

    2.2761423749
    
    

       There are six paths to visit the towns:

          1→ 2 → 3, 1 → 3 → 2, 2 → 1 → 3, 2 → 3 → 1, 3 → 1 → 2, and 3 → 2 → 1

          The length of the path

           1→ 2 → 3 is √(0−1)2+(0−0)2+√(1−0)2+(0−1)2=1+√2

           By calculating the lengths of the other paths in this way, we see that the average length of all routes is:

            ((1+√2)+(1+√2)+(2)+(1+√2)+(2)+(1+√2))/6=2.276142...

 


Sample Input 2

2
-879 981
-866 890

Sample Output 2

91.9238815543

There are two paths to visit the towns:

1→ 2 and 2 → 1

. These paths have the same length.


Sample Input 3

8
-406 10
512 859
494 362
-955 -475
128 553
-986 -885
763 77
449 310

Sample Output 3

7641.9817824387

 

题目大意:

在一个二维的座标系上,有n个城镇,每个城镇的座标(x_i,y_i),i\epsilon [1,2...n],

每访问一次城镇,会经过该城镇对应的座标,访问一次所有的城镇,会经历过所有城镇的座标,此时会根据你访问的顺序产生一条路径,(这种路径一共有N!种,题目中说明,城镇1->城镇2与城镇2->城镇1 算不同的情况),每条路径会产生一个距离值(根据两点间的距离公式,然后求和可得),问:N!种的路径距离值和的平均值。

思路:

一种是暴力求解,另一种是按贡献值算

注意,本题结果是浮点数,就算是double,题目要求的精度比较高(10^{-6}),如果处理不好肯能导致精度的丢失,直接导致WA

思路1:按贡献求

平均值=n个城镇任意两个城镇(城镇不重复)距离值*2/n的和所对应的值

代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
typedef int ll;
const ll maxn=100;
double sum=0.0;
double cnt=1;
ll pos[maxn][2]={0};
double distance(ll x1,ll y1,ll x2,ll y2){
	return sqrt( ( (x1-x2)*(x1-x2) )+((y1-y2)*(y1-y2) ));
} 

int main(){

	ios::sync_with_stdio(false);
	ll n;
	cin>>n;
	for(ll i=1;i<=n;i++){
		cnt*=i;
		cin>>pos[i][0]>>pos[i][1];	
	}
	int cs=0;
	for(ll i=1;i<=n;i++){
		for(ll j=i+1;j<=n;j++){
                 //防止Double精度丢失		
		  sum+=(distance(pos[i][0],pos[i][1],pos[j][0],pos[j][1]))*2/n;
		}
	}
	printf("%.10lf\n",sum);
	return 0;
}
//8
//-406 10
//512 859
//494 362
//-955 -475
//128 553
//-986 -885
//763 77
//449 310

推到过程如下

 

1>我们假设就三个城镇(1,2,3),共有6种情况(如下)

      1->2->3;1->3->2;2->1->3;2->3->1;3->1->2;3->2->1

     根据题意(城镇1->城镇2与城镇2->城镇1 算不同的情况)和观察可得(1->2>3与3->2->1)其实值是一样的

故我们继续拆分规模

6种情况和的总值   =》3总情况和的总值*2

============================================================

    1->2->3(1->2    2->3); 1->3->2 (1->3   3->2);2->1->3( 2->1  1->3);

     3->2->1(3->2  2->1)  ;    2->3->1 (2->3 3->1); 3->1->2(3->1 1->2);

=============================================================

    他们和的值1->2->3(1->2    2->3); 1->3->2 (1->3   3->2);2->1->3( 2->1  1->3);乘2==6种情况和的总值 

2>我们求个路径距离值和的平均数=》n!种情况和的总值  /  n

在拆分规模的过程中我们发现,其实每条路径值的和=连续n-1次  每次取出2个数的情况

(ps1: 1->2 # 1->3 # 2->3  ###   2->1#3->2#3-1  )

(ps2:两次取的数整体不重复,且取出的数最终每个数都要包含情况)

  (ps3: 上述6种情况和的总值都是由ps1中的内容按照次ps2的规则组合而来,而且可以得到的如下等式 ps4)

(  ps4:

6!种情况=(1->2  +  2->3)   +  (1->3 + 3->2) + ( 2->1 + 1->3) ==  (3->2 + 2->1)  +   (2->3 +3->1) +(3->1 + 1->2) 

     但(1->2  +  2->3)   +  (1->3 + 3->2) + ( 2->1 + 1->3) ==  (3->2 + 2->1)  +   (2->3 +3->1) +(3->1 + 1->2)  
       故==》( (1->2  +  2->3)   +  (1->3 + 3->2) + ( 2->1 + 1->3))(选其中的一种,算平均值,提出的2 会被约掉)

      把括号打开整理得==》 (1->2)+ (1->3) +(1->3)+ (2->1)+ (2->3)   +(3->2)

                                   ==>((1->2)+(1->3)+(2->3))* 2

)

分析ps4 的整理

可以排出3!个路径=》进一步划分【因为题意说顺序不同,视为不同走法,故得到了n!/2种不同结果值】

3种不同结果值(1->2  +  2->3)   , (1->3 + 3->2) , ( 2->1 + 1->3)

因为要算平均值,所以不管N!的路径如增加,最后的平均值==这三个不同的结果值和的平均值

=》n!/2个不重复结果的和 /n

==》n个元素两两排列不重复的和*2/n

故:

n!种情况和的总值=n个数不重复的全排练的和/n=>n个元素两两排列不重复的和*2/n

思路2:

暴力求解: 按照题意---递归遍历所有情况,然后把每次路径的平均值加和,易精度丢失

ps:不推荐,全当练习n个数全排练了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
typedef int ll;
const ll maxn=100;
double sum=0.0;
double cnt=1;
ll a[maxn]={0};
ll vis[maxn]={0};
ll pos[maxn][2]={0};
double distance(ll x1,ll y1,ll x2,ll y2){
    return sqrt( ( (x1-x2)*(x1-x2) )+((y1-y2)*(y1-y2) ));
} 
void solve(ll n,ll ct){
     if(ct==n+1){
	for(ll i=1;i<n;i++)
	 sum+=distance(pos[a[i]][0],pos[a[i]][1],pos[a[i+1]][0],pos[a[i+1]][1])/cnt;
     }
     else{
	for(ll i=1;i<=n;i++){
	   if(vis[i]==0){
		a[ct]=i;
		vis[i]=1;
		solve(n,ct+1);	
		vis[i]=0;
            }
        }
     }		
}
int main(){
	ios::sync_with_stdio(false);
	ll n;
	cin>>n;
	for(ll i=1;i<=n;i++){
          cnt*=i;	
          cin>>pos[i][0]>>pos[i][1];
	}
        solve(n,1);
        printf("%.10lf\n",sum);
	return 0;
}

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章