poj2728+最优比率生成树
2016-05-17 10:57
441 查看
题意:一个无向图,每条边有两个权值,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即可。
设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即可。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> using namespace std; struct node { double x,y,h; }p[1100]; double g[1100][1100],l[1100][1100],h[1100][1100]; double dis(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } const double mmax=1<<30; double prim(int n) { int pre[1100],vis[1100],i; double lowcost[1100]; memset(vis,0,sizeof(vis)); vis[1]=1; for(i=1;i<=n;i++) { pre[i]=1; lowcost[i]=g[1][i]; } int num=0; double sum=0; while(num<n-1) { double mmin=mmax; int vx; for(i=1;i<=n;i++) { if(!vis[i]&&lowcost[i]<mmin) { mmin=lowcost[i]; vx=i; } } vis[vx]=1; num++; sum+=g[vx][pre[vx]]; for(i=1;i<=n;i++) { if(!vis[i]&&g[vx][i]<lowcost[i]) { lowcost[i]=g[vx][i]; pre[i]=vx; } } } return sum; } int main() { int n,i,j; while(scanf("%d",&n)!=EOF&&n!=0) { for(i=1;i<=n;i++) scanf("%lf %lf %lf",&p[i].x,&p[i].y,&p[i].h); double minl=mmax,minh=mmax,maxl=-mmax,maxh=-mmax; for(i=1;i<=n;i++) { for(j=i;j<=n;j++) { if(i==j) { l[i][j]=0; h[i][j]=0; } else { l[i][j]=l[j][i]=dis(p[i].x,p[i].y,p[j].x,p[j].y); h[i][j]=h[j][i]=fabs(p[i].h-p[j].h); if(l[i][j]>maxl) maxl=l[i][j]; if(l[i][j]<minl) minl=l[i][j]; if(h[i][j]>maxh) maxh=h[i][j]; if(h[i][j]<minh) minh=h[i][j]; } } } double ll=minh/maxl; double rr=maxh/minl; while(rr-ll>1e-4) { double mid=(ll+rr)/2; for(i=1;i<=n;i++) for(j=i;j<=n;j++) g[i][j]=g[j][i]=h[i][j]-mid*l[i][j]; double ans=prim(n); if(ans>0) ll=mid; else rr=mid; } printf("%.3f\n",ll); } return 0; }
相关文章推荐
- ios彩票端 摇一摇的实现
- JavaScript 设计模式之工厂模式
- 最长上升子序列
- Android用户图片上传功能的实现
- Java中常见的集合之HashMap
- 学习练习 java面向对象梯形面积
- JavaWeb学习笔记—Servlet
- MySQL 创建库
- 浅析成员函数和常成员函数的调用
- Java-JVM的内存管理和垃圾回收
- 调整Toast字体大小
- 巧妙程序写法
- LeetCode 030 Substring with Concatenation of All Words
- 解决Maven报Plugin execution not covered by lifecycle configuration
- mysql事件
- retrofit 实现文件上传和下载
- 将cordova嵌入iOS应用
- nagios无法载入静态资源
- jquery 属性操作 attr () val() html()
- [Windows] IIS6 部署ISAPI