大概題意:ios
每兩個點中的邊權有兩個:一個是兩點座標的歐幾里得距離( horizontal distance),暫且成爲ai,第二個是兩點的海拔之差,稱爲bi.而後須要一個生成樹使sum(ai)\sum(bi)最小。git
這裏能夠引入分數規劃:咱們設ai\bi=k,那麼ai-bi*k=0算法
咱們只須要二分一個值mid,當ai-bi*mid=0時,這時的mid即是最優值。優化
對於每個mid,將每一條邊的邊權都變爲ai-bi*mid,而後求一個最小生成樹,若是總長是0,說明mid是答案,若是總長>0說明mid小了,讓mid變大,反之讓mid變小。spa
可是!!你覺得這樣就完了嗎?根本沒有!!!code
坑點:blog
一、這個點是一個徹底圖,也就是有足足n^2條邊,咱們使用的算法必定要盡力規避m,再見kruskal!,再見堆優化!甚至臨界表,再見!咱們必需要用沒有堆優化,使用鄰接矩陣的prim!ci
二、精度不能取0.0001或者0.001就ok了,必需要取到0.00001!get
三、二分時r必定不能開大,開打一點都會T,開到100就行,不要怕錯!!!string
四、終極大坑,最後的輸出不能用%lf,必須用%f,不要爲我爲何!廠長是我表哥!!
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> #include <cstdlib> #define REP(i,k,n) for(int i=k;i<=n;i++) #define in(a) a=read() #define MAXN 1000030 using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } int n; int x[1010],y[1010],d[1010]; int f[1010]; struct edge{ int u,v; double a,b; }old[10101010]; double map[1010][1010],dis[1010]; int vis[1010]; int total; inline double check(double k){ double sum=0; memset(dis,127,sizeof(dis)); memset(vis,0,sizeof(vis)); memset(map,127,sizeof(map)); REP(i,1,total) map[old[i].v][old[i].u]=map[old[i].u][old[i].v]=old[i].a-k*old[i].b; dis[1]=0; for(int i=1;i<=n;i++){ double minn=2147483647; int v=-1; for(int j=1;j<=n;j++) if(vis[j]==0 && (v==-1 || dis[j]<minn)){ minn=dis[j]; v=j; } sum+=dis[v]; vis[v]=1; for(int j=1;j<=n;j++) if(dis[j]>map[v][j]) dis[j]=map[v][j]; } return sum; } int main(){ while(cin>>n){ if(!n) break; total=0; REP(i,1,n) in(x[i]),in(y[i]),in(d[i]),x[i]++,y[i]++,d[i]++; REP(i,1,n) REP(j,1,i-1){ old[++total].a=abs(d[i]-d[j]); old[total].b=sqrt(abs(x[i]-x[j])*abs(x[i]-x[j])+abs(y[i]-y[j])*abs(y[i]-y[j])); old[total].u=i,old[total].v=j; } double l=0,r=100.0,mid,k; while(r-l>0.00001){ mid=(l+r)/2; k=check(mid); if(k>0) l=mid; if(k<0) r=mid; if(k==0) break; } printf("%.3f\n",mid); } return 0; } /* 5 2 3 3 3 2 10 5 1 3 5 7 6 7 8 4 */