题意:有n个村庄,给出每个村庄的坐标和海拔,
benifit为两点之间的水平距离,cost为两点的高度差,
现要求一棵树使得 cost / benift 最小,即求一个最优比例生成树
分析:01规划的应用
设x[i]等于1或0, 表示边取或者不取
则所求的比率 rate = ∑(cost[i] * x[i]) / ∑(benifit[i] * x[i])
设 z = ∑(cost[i] * x[i]) - rate * ∑(benifit[i] * x[i])
= ∑(d[i] * x[i])
其中d[i] = cost[i] - rate *benifit[i]
为了使rate最小,则z要最大
则可将d[i]看作边的权值,二分rate,再用prim求最小生成树
#include<stdio.h> #include<math.h> #include<string.h> #define eps 1e-6 #define INF 1e9 typedef struct{ double x,y,z; }point; int n; double cost[1010][1010],len[1010][1010],map[1010][1010]; double dis(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double prim(double rate) { int i,j,pos; double low[1010]; bool visit[1010]; for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) map[i][j]=map[j][i]=cost[i][j]-rate*len[i][j]; memset(visit,0,sizeof(visit)); pos=1; visit[pos]=true; for(i=1;i<=n;i++) low[i]=map[pos][i]; double min,s=0; for(i=1;i<n;i++){ min=INF; for(j=1;j<=n;j++) if(!visit[j]&&low[j]<min){ pos=j; min=low[j]; } if(min==INF) break; s+=min; visit[pos]=true; for(j=1;j<=n;j++){ if(!visit[j]&&map[pos][j]<low[j]) low[j]=map[pos][j]; } } return s; } double bin_search(double l,double r) { double mid; while(r-l>eps){ mid=(l+r)/2; if(prim(mid)>=0) l=mid; else r=mid; } return mid; } int main() { int i,j; point p[1010]; while(scanf("%d",&n)!=EOF){ if(n==0) break; for(i=1;i<=n;i++) scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z); for(i=1;i<=n;i++){ map[i][i]=0.0; for(j=i+1;j<=n;j++){ cost[i][j]=cost[j][i]=fabs(p[i].z-p[j].z); len[i][j]=len[j][i]=dis(p[i].x,p[i].y,p[j].x,p[j].y); } } double ans=bin_search(0.0,100.0); printf("%.3lf\n",ans); } return 0; }
poj 2728 Desert King (最优比率生成树)
原文地址:http://blog.csdn.net/acm_code/article/details/43273003