POJ 2728 Desert King
最优比率生成树
01 分数规划与MST的结合,注意总成本与总长度比值最小,不等价于总长度与总成本比值最大
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define eps 1e-6
using namespace std;
const int MAXN = 1005;
int init() {
int rv = 0, fh = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') fh = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
rv = (rv<<1) + (rv<<3) + c - '0';
c = getchar();
}
return fh * rv;
}
int n, x[MAXN], y[MAXN], hei[MAXN];
double val[MAXN][MAXN], cot[MAXN][MAXN], fin[MAXN][MAXN], l, r, mid, dis[MAXN];
bool f[MAXN];
double cal(int a, int b) {
return sqrt((double)(x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]));
}
bool chk(double x) {
memset(f, 0, sizeof(f));
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
fin[i][j] = cot[i][j] - x * val[i][j] ;
//if(x == 1.0) printf("%f ", fin[i][j]);
}
}
double ans = 0.0;
f[1] = 1;
for(int i = 1; i <= n; i++) {
dis[i] = fin[1][i];
}
for(int i = 1; i < n; i++) {
int k = 0;
double mi = 1e10;
for(int j = 1; j <= n; j++) {
if(!f[j]) {
if(mi > dis[j]) mi = dis[j], k = j;
}
}
if(!k) break;
f[k] = 1;
ans += dis[k];
for(int j = 1; j <= n; j++ ){
if(!f[j]) {
if(dis[j] > fin[k][j]) dis[j] = fin[k][j];
}
}
}
return (ans >= 0.0);
}
int main() {
while(1) {
n = init();
if(!n) break;
for(int i = 1; i <= n; i++) x[i] = init(), y[i] = init(), hei[i] = init();
l = r = mid = 0.0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
val[i][j] = cal(i, j);
r += val[i][j];
cot[i][j] = (double) abs(hei[i] - hei[j]);
}
}
r = 100.0;
while(r - l > eps) {
mid = (l + r) * 0.5;
if(chk(mid)) {
l = mid;
}else r = mid;
}
printf("%.3f\n", mid);
}
return 0;
}