poj 2728 (最优比率生成树)

题目链接: http://poj.org/problem?id=2728

题意: 在三维坐标系中,给定 N 个村庄, 要求在N个村庄之间连接水管,使其所有村庄相连(直接或间接),修水管的费用为z坐标之差, 路程为 两点在xoy面的投影距离, 要求  总花费 / 总路程  的比值最小。

裸的 最优比率生成树题目, 关于  最优比率生成树  http://www.cnblogs.com/lotus3x/archive/2009/03/21/1418480.html 这个博客,写的賊好。

此处AC代码用的 prim + 二分

#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

const int maxn = 1010;
const double inf = 0x3f3f3f3f;
const double eps = 1e-8;
int x[maxn],y[maxn],z[maxn];
double cost[maxn][maxn];    ///cost[i][j] 建造 i , j 村庄的花费
double dis[maxn][maxn];     ///dis[i][j]  i , j 村庄的距离
int mst[maxn];              ///mst[i]判断点 i 是否属于最小生成树, == -1 则属于
double lowcost[maxn];       ///lowcost[i] 以某个点为起点 到 i 点的最小距离
int n;

double cal(int i,int j){
    return sqrt(1.0*(x[i]-x[j])*(x[i]-x[j]) + 1.0*(y[i]-y[j])*(y[i]-y[j]));
}

double prim(int s,double rate){
    for(int i = 1;i <= n;i ++){
        mst[i] = s;
        lowcost[i] = cost[s][i] - rate * dis[s][i];
    }
    mst[s] = -1;
    int minid; double mi = inf;
    double sum = 0;
    for(int i = 1;i < n;i ++){
        mi = inf; minid = -1;
        for(int j = 2;j <= n;j ++){
            if(lowcost[j] < mi && mst[j] != -1){
                mi = lowcost[j];
                minid = j;
            }
        }
        if(minid != -1){
            sum += mi;
            mst[minid] = -1;
            for(int j = 2;j <= n;j ++){
                if(lowcost[j] > cost[minid][j] - rate * dis[minid][j] && mst[j] != -1){
                    lowcost[j] = cost[minid][j] - rate * dis[minid][j];
                    mst[j] = minid;         ///此题中, 此句可要可不要,因为只是起标记作用
                }
            }
        }
    }
    return sum;
}

int main()
{
    while(~scanf("%d",&n)){
        if(!n) break;
        for(int i = 1;i <= n;i ++)
            scanf("%d%d%d",&x[i],&y[i],&z[i]);
        for(int i = 1;i <= n;i ++){
            for(int j = 1;j <= n;j ++){
                if(i == j) continue;
                dis[i][j] = cal(i,j);
                cost[i][j] = abs(z[i] - z[j]);
            }
        }
        double l = 0.0,r = 100.0,mid;
        while(r - l > eps){
            mid = (l + r) / 2;
            if(prim(1,mid) >= 0) l = mid;
            else r = mid;
        }
        printf("%.3f\n",r);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/no_O_ac/article/details/81316040