1. 程式人生 > >編程之美初賽第一場

編程之美初賽第一場

不難 遍歷 weight 最好 ngx ane while www 整數

題目3 : 活動中心

時間限制:12000ms 單點時限:6000ms 內存限制:256MB

描寫敘述

A市是一個高度規劃的城市。可是科技高端發達的地方,居民們也不能忘記運動和鍛煉,因此城市規劃局在設計A市的時候也要考慮為居民們建造一個活動中心。方便居住在A市的居民們能隨時開展運動。鍛煉強健的身心。

城市規劃局希望活動中心的位置滿足下面條件:

1. 到全部居住地的總距離最小。

2. 為了方便活動中心的資源補給和其它器材的維護,活動中心必須建設在A市的主幹道上。


為了簡化問題。我們將A市擺在二維平面上,城市的主幹道看作直角坐標系平的X軸,城市中全部的居住地都能夠看成二維平面上的一個點。

如今。A市的城市規劃局希望知道活動中心建在哪兒最好。


輸入

第一行包含一個數T。表示數據的組數。

接下來包括T組數據,每組數據的第一行包括一個整數N。表示A市共同擁有N處居住地

接下來N行表示每處居住地的坐標。


輸出

對於每組數據。輸出一行“Case X: Y”,當中X表示每組數據的編號(從1開始)。Y表示活動中心的最優建造位置。我們建議你的輸出保留Y到小數點後6位或以上,不論什麽與標準答案的絕對誤差或者相對誤差在10-6以內的結果都將被視為正確。


數據範圍

小數據:1 ≤ T ≤ 1000, 1 ≤ N ≤ 10

大數據:1 ≤ T ≤ 10, 1 ≤ N ≤ 105

對於全部數據。坐標值都是整數且絕對值都不超過106



例子解釋

例子1:活動中心的最優建造位置為(1.678787, 0)



例子輸入
1
3
1 1
2 2
3 3
例子輸出
Case 1: 1.678787
分析:初看此題,感覺不難,目標是在X軸上找一個點,讓它距離全部點距離之和最小。可是一動手做才發現不知道從哪裏切入。由於假設從最小的X遍歷到最大的X的話,無法設置步長(題目精確到了10^-6),所以還得找其它方法。

1、對目標函數求導。目標函數是 y=((x-x1)^2+y1*y1)^1/2+((x-x2)^2+y2*y2)^1/2+...,我們的目標是找到它的最小值,對它求導後,令導數等於0,此時的 x 就是我們要找的目標函數極小值處的 x 。可是導數=0也不好解。繼續對導數求導發現其是恒大於0的,也就是說導數是遞增的。所以導數的值應該是由負到正變化的,故目標函數應該是先遞減後遞增,有極小值,我們對導數應用二分法,找到它等於0處的點;關鍵代碼例如以下:

while(fabs(l-h)>= 0.00000001){
      mid= (l+h)/2;
      if(calcu(mid)){  //計算導數值是否 >=0,若是。繼續往右找
         h= mid;
      }else{   //否則。往左找
         l= mid;
      }
}
//calcu函數關鍵部分。求導數值
for(int i= 0; i< len; ++i){
    a= mid-point[i].first;
    b= sqrt(a*a+(point[i].second*point[i].second));
    sum+=a/b;
 }
return sum>=0;


2、看到還有一位網友說,能夠用三分法(我還是頭一次聽說這個三分法。。),即找一個全局的中間點mid,再找一個右半部分的mid,比較二者的目標函數值。誰小就往那邊移動邊界;

    double midl,midr,le,re,lme,rme;
    while(maxX-minX>eps)
    {
       midl=(minX+maxX)/2;  //全局mid
       midr=(midl+maxX)/2;  //右半段的mid,故為三分
       lme=GetDis(midl);   //計算目標函數值,即距離之和
       rme=GetDis(midr);
       if(lme>rme)
         minX=midl;
       else maxX=midr;
    }


參考鏈接:

http://blog.csdn.net/kunlong0909/article/details/24120343

http://www.tuicool.com/articles/iEjMBzv

http://94it.net/a/jingxuanboke/2014/0419/302083_2.html

編程之美初賽第一場