POJ-2728-Desert King

来源:互联网 发布:数据库设计案例分析 编辑:程序博客网 时间:2024/05/23 00:04

POJ-2728-Desert King

http://poj.org/problem?id=2728

有N个村庄,给出每个村庄的坐标和海拔,,benifit为两点之间的距离,cost为两点的高度差,现在要求一棵树使得 cost / benift 最小,即求一个最优比例生成树

第一次遇见这种生成树,在网上找了个解法

假设sigma(h)/sigma(l)==K 均值K可取,即: sigma(h)==K*sigma(l)

 sigma(h)==K*(l1+l2+l3+...lm)

 sigma(h)==K*l1+K*l2+K*l3+...K*lm

 把原来的每个边的h都减去K*l

 即hi'=hi-li'==hi-li*K

 然后问题可以转换到求hi'这些边的最小生成树了

如果hi'这些边得最小生成树权值和<=0.0,说明K这个均值可取

对于k,二分求解即可

代码基本是模仿网上的

#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<cmath>using namespace std;#define MAXN 1010#define INF 9999999999struct Point{double x,y,h;};Point point[MAXN];double mat[MAXN][MAXN];double h[MAXN][MAXN];double l[MAXN][MAXN];int n;double head,tail;double dist(Point &a,Point &b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double prim(){int i,j,k;double ans=0.0,min;int visit[MAXN];double dis[MAXN];for(i=0;i<n;i++){dis[i]=mat[0][i];visit[i]=0;}dis[0]=1;visit[0]=1;for(i=1;i<n;i++){min=INF;for(j=0;j<n;j++)if(!visit[j]&&dis[j]<min){min=dis[j];k=j;}ans+=min;visit[k]=1;for(j=0;j<n;j++)if(!visit[j]&&dis[j]>mat[k][j])dis[j]=mat[k][j];}return ans;}int main(){int i,j;double maxc,minc,maxl,minl,mid;while(scanf("%d",&n),n){maxc=-INF;minc=INF;maxl=-INF;minl=INF;for(i=0;i<n;i++)scanf("%lf%lf%lf",&point[i].x,&point[i].y,&point[i].h);for(i=0;i<n-1;i++)for(j=i+1;j<n;j++){h[i][j]=h[j][i]=fabs(point[i].h-point[j].h);l[i][j]=l[j][i]=dist(point[i],point[j]);if(maxc<h[i][j])maxc=h[i][j];if(minc>h[i][j])minc=h[i][j];if(maxl<l[i][j])maxl=l[i][j];if(minl>l[i][j])minl=l[i][j];}head=minc/maxl;tail=maxc/minl;while(tail-head>1e-4){mid=(head+tail)/2;for(i=0;i<n-1;i++)for(j=i+1;j<n;j++)mat[i][j]=mat[j][i]=h[i][j]-mid*l[i][j];if(prim()<=0.0)tail=mid;elsehead=mid;}printf("%.3f\n",head);}return 0;}


原创粉丝点击