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
.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
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個城鎮,每個城鎮的座標,,
每訪問一次城鎮,會經過該城鎮對應的座標,訪問一次所有的城鎮,會經歷過所有城鎮的座標,此時會根據你訪問的順序產生一條路徑,(這種路徑一共有N!種,題目中說明,城鎮1->城鎮2與城鎮2->城鎮1 算不同的情況),每條路徑會產生一個距離值(根據兩點間的距離公式,然後求和可得),問:N!種的路徑距離值和的平均值。
思路:
一種是暴力求解,另一種是按貢獻值算
注意,本題結果是浮點數,就算是double,題目要求的精度比較高(),如果處理不好肯能導致精度的丟失,直接導致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;
}