题目描述
传送门
题意:给出n个点的坐标和海拔,两个点之间的距离为欧氏距离,花费为海拔差,求一个生成树,满足每公里的花费最小
题解
一个裸的最优比率生成树问题
二分R,然后每条边权记为
di=costi−R∗leni
然后求一个最小生成树,如果边权和小于0说明有更优解
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 1005
const double eps=1e-6;
int dcmp(double x)
{
if (x<=eps&&x>=-eps) return 0;
return (x>0)?1:-1;
}
int n;
double ans;
double x[N],y[N],h[N],a[N][N],b[N][N],d[N][N],minn[N];
bool vis[N];
double check(double R)
{
memset(minn,127,sizeof(minn));minn[1]=0;
memset(vis,0,sizeof(vis));
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
d[i][j]=a[i][j]-R*b[i][j];
for (int i=1;i<=n;++i)
{
int k=0;
for (int j=1;j<=n;++j)
if (!vis[j]&&minn[j]<minn[k])
k=j;
vis[k]=1;
for (int j=1;j<=n;++j)
if (!vis[j]&&d[k][j]<minn[j])
minn[j]=d[k][j];
}
double re=0;
for (int i=1;i<=n;++i) re+=minn[i];
return re;
}
double find()
{
double l=0.0,r=1e7,mid,now,ans=1e7;
while (dcmp(r-l)>0)
{
mid=(l+r)/2.0;
now=check(mid);
if (dcmp(now)<0) ans=r=mid;
else l=mid;
}
return ans;
}
int main()
{
while (~scanf("%d",&n))
{
if (!n) break;
for (int i=1;i<=n;++i) scanf("%lf%lf%lf",&x[i],&y[i],&h[i]);
if (n==1) {puts("0.000");continue;}
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
a[i][j]=fabs(h[i]-h[j]);
b[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
ans=find();
printf("%.3lf\n",ans);
}
}

本文介绍了一种解决特定生成树问题的算法——最优比率生成树。通过二分查找确定最优成本比,实现每公里花费最小的目标。文章详细阐述了算法步骤,并提供了完整的C++实现代码。
&spm=1001.2101.3001.5002&articleId=55250491&d=1&t=3&u=069a21f0c7254e3bb9b1369e43ace52d)
263

被折叠的 条评论
为什么被折叠?



