最小割

最优比率生成树

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

题意:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,

         建造水管距离为坐标之间的欧几里德距离(好象是叫欧几里德距离吧),费用为海拔之差

         现在要求方案使得费用与距离的比值最小

         http://www.cppblog.com/jh818012/articles/167743.html

 1 #include<iostream>
 2 #include<string.h>
 3 #include<stdio.h>
 4 #include<math.h>
 5 using namespace std;
 6 #define INF 10000000
 7 int x[1002],y[1002],h[1002],n;
 8 double  dis[1002][1002],high[1002][1002],d[1002],vis[1002];
 9 
10 double prim(double r)
11 {
12     int i,j;
13     for(i=2;i<=n;i++)
14         d[i]=high[1][i]-dis[1][i]*r;
15     memset(vis,0,sizeof(vis));
16     vis[1]=1;
17     double p=0;
18     for(i=1;i<n;i++)
19     {
20         double minn=INF;
21         int v;
22         for(j=1;j<=n;j++)
23             if(!vis[j]&&minn>d[j])
24             {
25                 minn=d[j];
26                 v=j;
27             }
28             p+=minn;
29             vis[v]=1;
30         
31             for(j=1;j<=n;j++)
32                 if(!vis[j])
33                     if(d[j]>high[v][j]-dis[v][j]*r)
34                         d[j]=high[v][j]-dis[v][j]*r;
35         
36     }
37     return p;
38 }
39 
40 int main()
41 {
42     int i,j,m,t;
43     while(scanf("%d",&n))
44     {
45     
46         if(n==0)
47             break;
48         double max=0.0;
49         for(i=1;i<=n;i++)    
50             scanf("%d%d%d",&x[i],&y[i],&h[i]);    
51     
52         for(i=1;i<=n;i++)
53             for(j=i+1;j<=n;j++)
54                 {
55                     double b;
56                     b=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
57                     dis[i][j]=dis[j][i]=sqrt(b);
58                     high[i][j]=high[j][i]=abs(h[i]-h[j]);
59                     if(max<high[i][j]/dis[i][j])
60                         max=high[i][j]/dis[i][j];
61                 }
62             //printf("max  %lf\n",max);
63                 double right=max,left=0.0, ans,mid;
64                 while(right>left)
65                 {
66                     mid=(right+left)/2;
67                     ans=prim(mid);
68                     if(fabs(ans-0.0)<0.0005)
69                         break;
70                     else if(ans>=0.0005)
71                         left=mid;
72                     else right=mid;
73                 }
74                 printf("%.3lf\n",mid);
75     }
76     return 0;
77 }
78                 
79                     
View Code

 

posted @ 2013-09-18 20:54  galaxy77  阅读(194)  评论(0编辑  收藏  举报