书P368
题目地址:https://ac.nowcoder.com/acm/contest/1056/C

① 0/1分数规划https://blog.nowcoder.net/n/70ad985a57bc4085aaee4d40fd2a9451

② Prim算法https://blog.nowcoder.net/n/012b92baab1f4ee59bb17b9bcb8dadb4

#include<bits/stdc++.h>
using namespace std;

const double inf=1e18;
const int N=15e4+10;
const int maxn=1e3+10;
const double eps=1e-5;

int n;
double cost[maxn][maxn],dis[maxn][maxn],x[maxn],y[maxn],z[maxn];
int vis[maxn];

double get_dis(int a,int b)
{
    return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));//求两点间距离 
}

int check(double x)//Prim算法求最大生成树边权之和是否非负 
{
    memset(vis,0,sizeof(vis));
    double sum=0,lowcost[maxn];
    for(int i=1;i<=n;i++)
    {
        lowcost[i]=cost[1][i]-x*dis[1][i];
    }
    for(int i=2;i<=n;i++)
    {
        double temp=inf;
        int k=-1;
        for(int j=2;j<=n;j++)
        {
            if(!vis[j]&&lowcost[j]<temp)
            {
                k=j;
                temp=lowcost[j];
            }
        }
        if(k==-1)
        {
            break;
        }
        vis[k]=1;
        sum+=temp;
        for(int j=2;j<=n;j++)
        {
            if(!vis[j]&&cost[k][j]-x*dis[k][j]<lowcost[j])
            {
                lowcost[j]=cost[k][j]-x*dis[k][j];
            }
        }
    }
    if(sum>=0)return 1;
    return 0;
}
int main()
{
    while(cin>>n&&n!=0)
    {
        for(int i=1;i<=n;i++)
        {
            cin>>x[i]>>y[i]>>z[i];
        }
        for(int i=1;i<=n-1;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                dis[i][j]=dis[j][i]=get_dis(i,j);//转化为无向图中的收益与代价 
                cost[i][j]=cost[j][i]=abs(z[i]-z[j]);
            }
        }
        double l=0.0,r=100.0;
        while(r-l>=eps)
        {
            double mid=(l+r)/2;
            if(check(mid))//判断mid比答案大还是小 
            {
                l=mid;
            }
            else
            {
                r=mid;
            }
        }
        printf("%.3f\n",r);
    }
    return 0;
}

来源:https://www.cnblogs.com/zhangchengc919/p/5684346.html