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;
}

 

 

 

 

 

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