最优比率生成树
是 01 分数规划的第二种类型
有带权图G, 对于图中每条边e[i], 都有benifit[i](收入)和cost[i](花费), 我们要求的是一棵生成树T, 它使得 , i∈T 最大(或最小).
这显然是一个具有现实意义的问题.
0-1分数规划
设x[i]等于1或0, 表示边e[i]是否属于生成树.
则我们所求的比率 r = , 0≤i<m .
为了使 r 最大, 设计一个子问题---> 让 z = 最大
, 并记为z(l). 我们可以兴高采烈地把z(l)看做以d为边权的最大生成树的总权值.
然后明确两个性质:
1. z单调递减
证明: 因为cost为正数, 所以z随l的减小而增大.
2. z( max(r) ) = 0
证明: 若z( max(r) ) < 0, , 可化为 max(r) < max(r). 矛盾;
若z( max(r) ) >= 0, 根据性质1, 当z = 0 时r最大.
复杂度
时间 O( O(MST) * log max(r) )
空间 O( O(MST) )
例如: poj 2728
采用 prme 最小生成树 + 二分判断,,
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <string.h>
//#include <bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
const int maxn = 1005;
using namespace std;
const double esp = 1e-5;
const int inf = 0x3f3f3f3f;
int n,k;
struct node{
int x,y,z;
}p[maxn];
double edge[maxn][maxn];
double s[maxn];
int head[maxn*2];
double dis(int x,int y)
{
return sqrt(1.0*(p[x].x-p[y].x)*(p[x].x-p[y].x) + 1.0* (p[x].y-p[y].y)*(p[x].y-p[y].y));
}
bool prime(double mid)
{
double sum = 0;
int st = 1;
rep(i,1,n+1)
{
head[i] = st;
s[i] = abs(p[st].z-p[i].z) - mid*edge[st][i];
}
head[st] = -1;
rep(i,1,n)
{
double mi = inf*1.0;
int v = -1;
rep(j,1,n+1)
{
if( head[j]!=-1 && s[j] < mi)
{
v = j;
mi = s[j];
}
}
if(v!=-1)
{
head[v] = -1;
sum += s[v];
rep(j,1,n+1)
{
double te = abs(p[v].z-p[j].z)-mid*edge[v][j];
if( head[j] !=-1 && te < s[j])
{
head[j] = v;
s[j] = te;
}
}
}
}
return sum>=0? true:false;
}
int main()
{
while(~scanf("%d",&n),n)
{
rep(i,1,n+1)
scanf("%d %d %d",&p[i].x,&p[i].y,&p[i].z);
rep(i,1,n+1)
rep(j,1,n+1)
edge[i][j] = dis(i,j);
double l= 0, r = 1000.0;
while(l +esp < r)
{
double mid = (l+r)*1.0/2;
if( prime(mid))
l = mid;
else
r = mid;
}
printf("%.3f\n",r);
}
return 0;
}