最优比率生成树问题,就是01分数规划在树上的应用
是一类求解在树上选一些边,是这些边的花费比长度最大的问题,多次prime就好
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=2050;
const double eps=1e-7;
int n,vis[M];
double maxx;
double x[M],y[M],z[M],map[M][M];
double cost[M][M],len[M][M],dis[M];
double dpow(int i,int k)
{
return (double)sqrt((x[i]-x[k])*(x[i]-x[k])+(y[i]-y[k])*(y[i]-y[k]));
}
void built()
{
maxx=0.0;
for (int i=1;i<=n;i++)
for (int k=i+1;k<=n;k++)
cost[i][k]=cost[k][i]=fabs(z[i]-z[k]),len[k][i]=len[i][k]=dpow(i,k),maxx=max(maxx,cost[i][k]/len[i][k]);
return ;
}
double prime()
{
for (int i=1;i<=n;i++) dis[i]=map[1][i];
fill(vis,vis+n+1,0);vis[1]=1;double ans=0;
for (int i=2;i<=n;i++)
{
double minn=0x3f3f3f;
int get;
for (int k=1;k<=n;k++)
{
if (!vis[k]&&dis[k]<minn)
get=k,minn=dis[k];
}
if (minn==0x3f3f3f) break;
vis[get]=1;ans+=minn;
for (int k=1;k<=n;k++)
if (!vis[k])
dis[k]=min(dis[k],map[get][k]);
}
return ans;
}
bool check(double mid)
{
for (int i=1;i<=n;i++)
for (int k=i+1;k<=n;k++)
map[i][k]=map[k][i]=cost[i][k]-mid*len[i][k];
return prime()>=0;
}
int main()
{
while (~scanf("%d",&n)&&n)
{
for (int i=1;i<=n;i++)
cin>>x[i]>>y[i]>>z[i];
built();
double l=0.0,r=maxx;
while (r-l>=eps)
{
double mid=(l+r)/2.0;
if (check(mid)) l=mid;
else r=mid;
}
printf("%.3lf\n",l);
}
return 0;
}