poj2728+最优比率生成树

题意:一个无向图,每条边有两个权值,h和l,要求一个生成树,使得所有边的h的和比上l的和最小。

 

设x[i]等于1或0, 表示边e[i]是否属于生成树.

则我们所求的比率       r = ∑(benifit[i] * x[i]) / ∑(cost[i] * x[i]), 0≤i<m .

为了使 r 最小, 设计一个子问题---> 让     z = ∑(benifit[i] * x[i]) - k * ∑(cost[i] * x[i]) = ∑(d[i] * x[i]) 最小 (d[i] = benifit[i] - k * cost[i]) , 并记为z(k). 我们可以把z(k)看做以d为边权的最小生成树的总权值.(如果求r最大应该使用最大生成树).

由于cost[i]>0,所以k增大则z减小,z在k上单调递减。

接下来便是二分k

当z<0,即k>∑(benifit[i] * x[i])/∑(cost[i] * x[i]).而我们要求k尽量大z才会小,这样k无上限,矛盾。

故z应>=0,由于z在k上单调递减,所以要使r最小,则z要最小,则k要最大,k不能大到使z<0,所以k最大大到使z=0.

二分k使z=0即可。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstdlib>
 6 using namespace std;
 7 struct node
 8 {
 9     double x,y,h;
10 }p[1100];
11 double g[1100][1100],l[1100][1100],h[1100][1100];
12 double dis(double x1,double y1,double x2,double y2)
13 {
14     return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
15 }
16 const double mmax=1<<30;
17 double prim(int n)
18 {
19     int pre[1100],vis[1100],i;
20     double lowcost[1100];
21     memset(vis,0,sizeof(vis));
22     vis[1]=1;
23     for(i=1;i<=n;i++)
24     {
25         pre[i]=1;
26         lowcost[i]=g[1][i];
27     }
28     int num=0;
29     double sum=0;
30     while(num<n-1)
31     {
32         double mmin=mmax;
33         int vx;
34         for(i=1;i<=n;i++)
35         {
36             if(!vis[i]&&lowcost[i]<mmin)
37             {
38                 mmin=lowcost[i];
39                 vx=i;
40             }
41         }
42         vis[vx]=1;
43         num++;
44         sum+=g[vx][pre[vx]];
45         for(i=1;i<=n;i++)
46         {
47             if(!vis[i]&&g[vx][i]<lowcost[i])
48             {
49                 lowcost[i]=g[vx][i];
50                 pre[i]=vx;
51             }
52         }
53     }
54     return sum;
55 }
56 int main()
57 {
58     int n,i,j;
59     while(scanf("%d",&n)!=EOF&&n!=0)
60     {
61         for(i=1;i<=n;i++)
62         scanf("%lf %lf %lf",&p[i].x,&p[i].y,&p[i].h);
63         double minl=mmax,minh=mmax,maxl=-mmax,maxh=-mmax;
64         for(i=1;i<=n;i++)
65         {
66              for(j=i;j<=n;j++)
67              {
68                  if(i==j)
69                  {
70                      l[i][j]=0;
71                      h[i][j]=0;
72                  }
73                  else
74                  {
75                      l[i][j]=l[j][i]=dis(p[i].x,p[i].y,p[j].x,p[j].y);
76                      h[i][j]=h[j][i]=fabs(p[i].h-p[j].h);
77                      if(l[i][j]>maxl) maxl=l[i][j];
78                  if(l[i][j]<minl) minl=l[i][j];
79                  if(h[i][j]>maxh) maxh=h[i][j];
80                  if(h[i][j]<minh) minh=h[i][j];
81                  }
82              }
83         }
84         double ll=minh/maxl;
85         double rr=maxh/minl;
86         while(rr-ll>1e-4)
87         {
88             double mid=(ll+rr)/2;
89             for(i=1;i<=n;i++)
90                 for(j=i;j<=n;j++)
91                     g[i][j]=g[j][i]=h[i][j]-mid*l[i][j];
92                     double ans=prim(n);
93             if(ans>0)   ll=mid;
94             else rr=mid;
95         }
96         printf("%.3f\n",ll);
97     }
98     return 0;
99 }

 

posted @ 2016-03-16 22:09  2014551532  阅读(172)  评论(0编辑  收藏  举报