Desert King

POJ

题意:N个村庄,给出每个村庄的坐标和海拔,两个村庄之间的距离就用两点之间距离公式来求即可,两个村庄之间修路的费用为海拔之差,构建一棵生成树,使得费用之和与距离之和的比值最小?

分析:01分数规划.设每条边的权值为\(high[i][j]-mid*dist[i][j]\).因为是稠密图,所以只能Prim跑最小生成树.

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
const int N=1005;
int n,a[N],b[N],c[N],vis[N],path[N],high[N][N];
double Map[N][N],dis[N];
double eps=1e-6,dist[N][N];
inline double Prim(double mid){
    int i,j;  
    for(i=1;i<=n;i++) 
    for(j=i+1;j<=n;j++)  
        Map[i][j]=Map[j][i]=high[i][j]-mid*dist[i][j];  
    for(i=1;i<=n;i++){  
        dis[i]=Map[1][i];  
        vis[i]=0;  
        path[i]=1;  
    }  
    dis[1]=0;vis[1]=1;  
    int k;  
    for(i=1;i<n;i++){  
    double tmp=1e9;  
    for(j=1;j<=n;j++)  
        if(!vis[j]&&tmp>dis[j]){  
            k=j;  
            tmp=dis[j];  
        }  
        vis[k]=1;  
        for(j=1;j<=n;j++)  
            if(!vis[j]&&dis[j]>Map[k][j]){  
            dis[j]=Map[k][j];  
            path[j]=k;  
        }  
    }  
    double c=0,d=0;  
    for(i=1;i<=n;i++){  
        c+=high[i][path[i]];  
        d+=dist[i][path[i]];  
    }  
    return c/d;  
}
int main(){
    while(1){
        n=read();if(!n)return 0;
        for(int i=1;i<=n;i++)
            a[i]=read(),b[i]=read(),c[i]=read();    
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
                dist[i][j]=dist[j][i]=sqrt(1.0*(a[i]-a[j])*(a[i]-a[j])+1.0*(b[i]-b[j])*(b[i]-b[j]));
                high[i][j]=high[j][i]=abs(c[i]-c[j]);
            }
        }
        double l=0,r=0;  
        while(1){  
            r=Prim(l);  
            if(fabs(l-r)<=eps)break;  
            l=r;  
        }  
        printf("%.3f\n",l);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/PPXppx/p/10828098.html