[POJ2728]Desert King(01分数规划)

本文介绍了一种解决特定生成树问题的算法——最优比率生成树。通过二分查找确定最优成本比,实现每公里花费最小的目标。文章详细阐述了算法步骤,并提供了完整的C++实现代码。

题目描述

传送门
题意:给出n个点的坐标和海拔,两个点之间的距离为欧氏距离,花费为海拔差,求一个生成树,满足每公里的花费最小

题解

一个裸的最优比率生成树问题
二分R,然后每条边权记为 di=costiRleni
然后求一个最小生成树,如果边权和小于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);
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值