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;
}

posted on 2019-05-07 21:07  PPXppx  阅读(181)  评论(0编辑  收藏  举报