POJ 2728 Desert King(最优比率生成树)
题意:
每条路径有一个 cost 和 dist,求图中 sigma(cost) / sigma(dist) 最小的生成树。
思路:
1. sigma(cost)/sigma(dist) <= r 有 cost - r * dist <= 0
2. r = 0 当然是理想的初始状态,我们不断尝试 r 使结果不断逼近最优值,方能得到结果。
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 1010;
const double INFS = 1e15;
const double eps = 1e-5;
double x[MAXN], y[MAXN], z[MAXN];
double dist[MAXN][MAXN], cost[MAXN][MAXN], map[MAXN][MAXN], d[MAXN];
int p[MAXN], n;
bool vis[MAXN];
double prim(double ratio) {
for (int i = 1; i <= n; i++) {
map[i][i] = 0.0;
for (int j = i+1; j <= n; j++)
map[i][j] = map[j][i] = cost[i][j] - ratio*dist[i][j];
}
for (int i = 1; i <= n; i++)
d[i] = map[1][i], vis[i] = false, p[i] = 1;
vis[1] = true;
for (int k = 1, j; k < n; k++) {
double mind = INFS;
for (int i = 2; i <= n; i++)
if (!vis[i] && mind > d[i])
mind = d[i], j = i;
vis[j] = true;
for (int i = 2; i <= n; i++)
if (!vis[i] && d[i] > map[j][i])
d[i] = map[j][i], p[i] = j;
}
double d1 = 0, c1 = 0;
for (int i = 2; i <= n; i++) {
d1 += dist[i][p[i]];
c1 += cost[i][p[i]];
}
return c1 / d1;
}
int main() {
while (scanf("%d", &n) && n) {
for (int i = 1; i <= n; i++)
scanf("%lf%lf%lf", &x[i], &y[i], &z[i]);
for (int i = 1; i <= n; i++) {
dist[i][i] = cost[i][i] = 0.0;
for (int j = i+1; j <= n; j++) {
dist[i][j] = dist[j][i] = sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]));
cost[i][j] = cost[j][i] = fabs(z[i] - z[j]);
}
}
double r1 = 0.0, r2 = 0.0;
while (true) {
r2 = prim(r1);
if (fabs(r1 - r2) < eps)
break;
r1 = r2;
}
printf("%.3lf\n", r1);
}
return 0;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------