您的位置:首页 > 其它

poj2728+最优比率生成树

2016-05-17 10:57 387 查看
题意:一个无向图,每条边有两个权值,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即可。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: