题目大意是:给你坐标上一些点,然后你需要用一些边把他们连接起来,边有费用和长度,求总费用和总长度最小比值。
二分答案:
每边有两权值(a,b),求∑a/ ∑b最小的生成树.
设∑a/ ∑b=k --> ∑a=k*∑b --->a1+a2+...an = k*(b1+b2+..bn) ---->∑(ai-k*bi)==0
即边权变为a-k*b后求MST,看是否<0,如果<0则说明k太大了。>0说明k太小了。
ps:有种迭代的方法。看没太懂。下次看。
1 // File Name: 2728.cpp 2 // Author: Missa 3 // Created Time: 2013/2/23 星期六 21:36:48 4 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<algorithm> 9 #include<cmath> 10 #include<queue> 11 #include<stack> 12 #include<string> 13 #include<vector> 14 #include<cstdlib> 15 #include<map> 16 #include<set> 17 using namespace std; 18 #define CL(x,v) memset(x,v,sizeof(x)); 19 #define R(i,st,en) for(int i=st;i<en;i++) 20 const int maxn = 1e3+5; 21 const int inf = 0x3f3f3f3f; 22 const double eps = 1e-5; 23 int n; 24 struct Point 25 { 26 int x,y,z; 27 Point(){} 28 Point(int x,int y,int z):x(x),y(y),z(z){} 29 }; 30 double h[maxn][maxn];//村子的高度差 31 double g[maxn][maxn];//村子的距离 32 double prim(int src,double k)//源点,二分的答案k 33 { 34 double ans=0.0; 35 double dis[maxn]; 36 bool vis[maxn]; 37 R(i,1,n+1) 38 { 39 vis[i]=0; 40 dis[i]=h[src][i]-k*g[src][i]; 41 } 42 vis[src]=1; 43 R(i,1,n) 44 { 45 double MIN=inf; 46 int flag=-1; 47 R(j,1,n+1) 48 { 49 if(!vis[j] && dis[j]<MIN) 50 { 51 flag=j; 52 MIN=dis[j]; 53 } 54 } 55 if(flag==-1) break; 56 vis[flag]=1; 57 ans+=MIN; 58 R(j,1,n+1) 59 if(!vis[j] && h[flag][j]-k*g[flag][j]<dis[j]) 60 dis[j]=h[flag][j]-k*g[flag][j]; 61 } 62 return ans; 63 } 64 65 int main() 66 { 67 while(~scanf("%d",&n)) 68 { 69 if(!n) break; 70 int x,y,z,mx=0; 71 vector<Point> v; 72 v.clear(); 73 R(i,1,n+1) 74 { 75 scanf("%d%d%d",&x,&y,&z); 76 v.push_back(Point(x,y,z)); 77 if(mx<z) 78 mx=z; 79 } 80 R(i,0,n) 81 R(j,i,n) 82 { 83 h[i+1][j+1]=h[j+1][i+1]=fabs(v[i].z-v[j].z); 84 g[i+1][j+1]=g[j+1][i+1]=sqrt((v[i].x-v[j].x)*(v[i].x-v[j].x) + (v[i].y-v[j].y)*(v[i].y-v[j].y)); 85 } 86 /*R(i,1,n+1) 87 { 88 R(j,1,n+1) 89 cout<<g[i][j]<<" "; 90 cout<<endl; 91 }*/ 92 /* 93 double l=0.0,r=mx; 94 while(r-l>eps) 95 { 96 double m=(l+r)/2.0; 97 if(prim(1,m)<=0) 98 r=m; 99 else 100 l=m; 101 } 102 */ 103 double l=0,r=0; 104 while(1) 105 { 106 l=prim(1,r); 107 if(fabs(l-r)<eps) break; 108 r=l; 109 cout<<l<<endl; 110 } 111 printf("%.3f\n",l); 112 } 113 return 0; 114 }