poj 2728 最优比率生成树
思想的话看这里
http://www.cnblogs.com/lotus3x/archive/2009/03/21/1418480.html
二分法:
/*
the length of the channel is the horizontal distance between the two villages.
The cost of the channel is the height of the lifter.
最优比率生成树
poj 2728
目标:min{∑costi/∑leni}
逼近的思想,∑costi/∑leni<=x,即 ∑(costi-x*leni)<=0 是一个单调递减函数
即求边为costi-x*leni的 MST
*/
#include<stdio.h>
#include<string.h>
#include<math.h>
const double inf = 1e20;
const int N = 1010;
const double eps = 1e-8;
struct point {
double x,y,z;
}p[N];
int n,m;
int flag[N];
double D[N];
double len[N][N];
double cost[N][N];
double map[N][N];
double prime()
{
int i,v,k;
double ret=0,mi;
for(i=1;i<=n;i++){
flag[i]=0;
D[i]=inf;
}D[1]=0;flag[1]=1;v=1;
for(k=1;k<n;k++){
for(i=1;i<=n;i++)if(!flag[i]){
if(map[v][i]<D[i])
D[i]=map[v][i];
}
mi=inf;
for(i=1;i<=n;i++)
if(!flag[i]&&D[i]<mi)
mi=D[v=i];
flag[v]=1;
ret+=mi;
}
// printf("ret=%.2lf\n",ret);
return ret;
}
double dis(point a,point b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double solve(double mid)
{
int i,j;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
map[i][j]=map[j][i]=cost[i][j]-mid*len[i][j];
return prime();
}
int main()
{
int i,j,k;
while(scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
len[i][j]=len[j][i]=dis(p[i],p[j]);
cost[i][j]=cost[j][i]=fabs(p[i].z-p[j].z);
}
double a=0,b;
for(i=1;i<=n;i++)
map[i][i]=0.0;
double l=0.0,r=100.0,mid;
while(fabs(l-r)>eps)
{
mid=(l+r)/2;
if(solve(mid)>eps) l=mid;
else r=mid;
}
printf("%.3lf\n",r);
}
return 0;
}
迭代法:不用去管上下界,随意代入即可,此时求的是∑costi/∑leni的值,代码修改一下就好,迭代法的效率灰常高啊,上面的是迭代

#include<stdio.h>
#include<string.h>
#include<math.h>
const double inf = 1e20;
const int N = 1010;
const double eps = 1e-8;
struct point {
double x,y,z;
}p[N];
int n,m;
int flag[N];
double D[N],len[N][N],cost[N][N],map[N][N];
int pre[N];
double dis(point a,point b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double prime()
{
int i,v,k;
double cost=0,len=0,mi;
memset(flag,0,sizeof(flag));
for(i=1;i<=n;i++) D[i]=inf;
D[1]=0;flag[1]=1;v=1;
for(k=1;k<n;k++){
for(i=1;i<=n;i++)
if(!flag[i]&&map[v][i]<D[i]){
D[i]=map[v][i];
pre[i]=v;
}
mi=inf;
for(i=1;i<=n;i++)if(!flag[i]&&D[i]<mi)
mi=D[v=i];
flag[v]=1;
cost+=fabs(p[pre[v]].z-p[v].z);
len+=dis(p[pre[v]],p[v]);
}
return cost/len;
}
double solve(double mid)
{
int i,j;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
map[i][j]=map[j][i]=cost[i][j]-mid*len[i][j];
return prime();
}
int main()
{
int i,j;
while(scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
len[i][j]=len[j][i]=dis(p[i],p[j]);
cost[i][j]=cost[j][i]=fabs(p[i].z-p[j].z);
}
for(i=1;i<=n;i++)
map[i][i]=0.0;
double a=0,b;
while(1)
{
b=solve(a);
if(fabs(a-b)<eps) break;
a=b;
}
printf("%.3lf\n",b);
}
return 0;
}

浙公网安备 33010602011771号