POJ2728 Desert King 題解 最優比率生成樹 01分數規劃

題目鏈接:http://poj.org/problem?id=2728

題目大意:

給你一個無向圖,每條邊有一個價值和長度,求一棵生成樹,其對應的價值和與長度和的幣值最小。

解題思路:
01分數規劃。對每一個 \(mid\),以 \(a_i - mid \times b_i\) 爲邊求最小生成樹,判斷最小生成樹的長度是否 \(\ge 0\)

示例代碼:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn = 1010;
int n, x[maxn], y[maxn], z[maxn];
double dis[maxn][maxn], cost[maxn];
bool vis[maxn];
bool prim(double mid) {
    memset(vis, 0, sizeof(bool)*n);
    for (int i = 0; i < n; i ++) {
        for (int j = 0; j < i; j ++) {
            dis[i][j] = dis[j][i] = abs(z[i] - z[j]) - mid * sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]));
        }
    }
    cost[0] = 0;
    for (int i = 1; i < n; i ++) cost[i] = 1e9;
    double ans = 0;
    for (int j = 0; j < n; j ++) {
        int u = -1;
        for (int i = 0; i < n; i ++) if (!vis[i] && (u == -1 || cost[u] > cost[i])) u = i;
        if (u == -1) break;
        ans += cost[u];
        vis[u] = true;
        for (int i = 0; i < n; i ++) if (!vis[i] && dis[u][i] < cost[i]) cost[i] = dis[u][i];
    }
    return ans >= 0;
}
int main() {
    while (~scanf("%d", &n) && n) {
        for (int i = 0; i < n; i ++) scanf("%d%d%d", x+i, y+i, z+i);
        double L = 0, R = 100.0;
        while (R - L > 1e-4) {
            double mid = (L + R) / 2;
            if (prim(mid)) L = mid;
            else R = mid;
        }
        printf("%.3f\n", L);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章