# POJ 2728 Desert King（最优比例生成树）

0-1分数规划

1.  z单调递减

证明: 因为cost为正数, 所以z随l的减小而增大.

2.  z( max(r) ) = 0

证明: 若z( max(r) ) < 0, ∑(benifit[i] * x[i]) - max(r) * ∑(cost[i] * x[i]) < 0, 可化为 max(r) < max(r). 矛盾;

若z( max(r) ) >= 0, 根据性质1, 当z = 0 时r最大.

#include <queue>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int N = 1e3 + 5;

double d[N],w[N][N];

bool vis[N];

double prim(int n)
{
memset(vis,false,sizeof(vis));
memset(d,127,sizeof(d));
int u = 1 , times = 0;
double ans = 0;
while(++times < n)
{
vis[u] = true;
for(int v=1;v<=n;v++)
if(!vis[v] && w[u][v] < d[v])
d[v] = w[u][v];
double mmin = d[0];
for(int v=1;v<=n;v++)
if(!vis[v] && mmin > d[v])
mmin = d[v] , u = v;
if(mmin == d[0])
return -1;
ans += mmin;
}
return ans;
}

struct Point
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
}
int sqr(int x){
return x * x;
}
double dis(const Point& P){
return sqrt( sqr(x-P.x)*1.0 + sqr(y-P.y) );
}
int cost(const Point& P){
return abs(z-P.z);
}
}A[N];

double dis[N][N];

int cost[N][N];

void build(int n,double L)
{
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
w[i][j] = w[j][i] = cost[i][j] - L*dis[i][j];
}

const double eps = 1e-5;

int main()
{
int n;
while(scanf("%d",&n),n)
{
for(int i=1;i<=n;i++)
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
dis[i][j] = dis[j][i] = A[i].dis(A[j]);
cost[i][j] = cost[j][i] = A[i].cost(A[j]);
}
double l = 0 , r = 100;
while(r-l > eps)
{
double mid = (l+r) / 2;
build(n,mid);
if(prim(n) > eps)
l = mid;
else
r = mid;
}
printf("%.3f\n",r);
}
return 0;
}

#include <queue>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int N = 1e3 + 5;

double dis[N][N];

int cost[N][N];

double d[N],w[N][N];

bool vis[N];

int pre[N];

double prim(int n)
{
if(n == 1)
return 0;
memset(vis,false,sizeof(vis));
memset(d,127,sizeof(d));
int u = 1 , times = 0;
double dis = 0;
int cost = 0;
while(++times < n)
{
vis[u] = true;
for(int v=1;v<=n;v++)
if(!vis[v] && w[u][v] < d[v])
d[v] = w[u][v] , pre[v] = u;
double mmin = d[0];
for(int v=1;v<=n;v++)
if(!vis[v] && mmin > d[v])
mmin = d[v] , u = v;
if(mmin == d[0])
return -1;
cost += ::cost[pre[u]][u];
dis += ::dis[pre[u]][u];
}
return cost / dis;
}

struct Point
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
}
int sqr(int x){
return x * x;
}
double dis(const Point& P){
return sqrt( sqr(x-P.x)*1.0 + sqr(y-P.y) );
}
int cost(const Point& P){
return abs(z-P.z);
}
}A[N];

void build(int n,double L)
{
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
w[i][j] = w[j][i] = cost[i][j] - L*dis[i][j];
}

const double eps = 1e-5;

int main()
{
int n;
while(scanf("%d",&n),n)
{
for(int i=1;i<=n;i++)
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
dis[i][j] = dis[j][i] = A[i].dis(A[j]);
cost[i][j] = cost[j][i] = A[i].cost(A[j]);
}
double last = -1 , cur = 0;
while(fabs(cur-last) > eps)
{
last = cur;
build(n,last);
cur = prim(n);
}
printf("%.3f\n",cur);
}
return 0;
}