Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 21766 | Accepted: 6087 |
Description
Input
Output
Sample Input
4 0 0 0 0 1 1 1 1 2 1 0 3 0
Sample Output
1.000
题意:有n个村庄,分别给出每个村庄的地理坐标(xi,yi)和海拔hi,要求在村庄之间修一些河道,使这些河道联通所有的村庄,不同的村庄由于海拔的差异需要修水泵,每个水泵的费用为这两个村庄的海拔差值,且每个水泵为一条河道所用,要求所有的费用/总的河道长度比率最小
分析:r=sigma(h[i][j])/sigma(l[i][j]),设R为最优值,则r>=R;(h[i][j]代表修每条河道的费用,l[i][j]代表每条河道的长度,sigma()为生成树里面的边)
即:sigma(h[i][j])/sigma(l[i][j])>=R,所以:h[r]=sigma(h[i][j])-r*sigma(l[i][j])>=0;
所以对于每一个r对应的h(r)的最小生成树>=0
当h(r)<0的时候减小r的值,否则增大r的值,逐渐二分使h(r)=0即可;
方法一:二分法
#include"stdio.h" #include"string.h" #include"math.h" #define inf 0x3f3f3f3f #define M 2009 #define eps 1e-7 struct node { int x,y,h; }p[M]; double dist(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y)); } double dis[M],G[M][M],L[M][M]; int use[M]; double dij(int n,int s) { double sum=0; memset(use,0,sizeof(use)); for(int i=1;i<=n;i++) dis[i]=inf; dis[s]=0; for(int i=1;i<=n;i++) { double mini=inf; int id=-1; for(int j=1;j<=n;j++) { if(!use[j]&&dis[j]<mini) { mini=dis[j]; id=j; } } if(id==-1)break; sum+=dis[id]; use[id]=1; for(int j=1;j<=n;j++) { if(!use[j]&&dis[j]>G[id][j]) dis[j]=G[id][j]; } } return sum; } double solve(int n,double r) { for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) G[i][j]=G[j][i]=fabs(p[i].h*1.0-p[j].h*1.0)-L[i][j]*r+1000000000.0; } return dij(n,1)-(n-1)*1000000000.0; } int main() { int n; while(scanf("%d",&n),n) { double l=0,r=0,mid; for(int i=1;i<=n;i++) { scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].h); r+=p[i].h; } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { L[i][j]=L[j][i]=dist(p[i],p[j]); } } while(r-l>eps) { mid=(l+r)/2; double msg=solve(n,mid); if(msg<0) { r=mid; } else { l=mid; } } printf("%.3lf\n",r); } return 0; }
方法二:迭代法
#include"stdio.h" #include"string.h" #include"math.h" #define inf 0x3f3f3f3f #define M 2009 #define eps 1e-6 struct node { int x,y,h; }p[M]; double dist(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y)); } double dis[M],G[M][M],L[M][M]; int use[M],pre[M]; double dij(int n,int s) { double sum=0,cost=0,leng=0; memset(use,0,sizeof(use)); for(int i=1;i<=n;i++) { dis[i]=inf; pre[i]=-1; } dis[s]=0; for(int i=1;i<=n;i++) { double mini=inf; int id=-1; for(int j=1;j<=n;j++) { if(!use[j]&&dis[j]<mini) { mini=dis[j]; id=j; } } if(id==-1)break; sum+=dis[id]; use[id]=1; if(pre[id]!=-1) { cost+=fabs(p[id].h*1.0-p[pre[id]].h); leng+=L[id][pre[id]]; } for(int j=1;j<=n;j++) { if(!use[j]&&dis[j]>G[id][j]) { dis[j]=G[id][j]; pre[j]=id; } } } return cost/leng; } double solve(int n,double r) { for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { G[i][j]=G[j][i]=fabs(p[i].h*1.0-p[j].h*1.0)-L[i][j]*r+1000000000.0; } } return dij(n,1); } int main() { int n; while(scanf("%d",&n),n) { for(int i=1;i<=n;i++) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].h); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) L[i][j]=L[j][i]=dist(p[i],p[j]); double x0=0,x; while(1) { x=solve(n,x0); if(fabs(x-x0)<eps) break; x0=x; } printf("%.3lf\n",x); } return 0; }