• poj2728(最小比率生成树)


    poj2728

    题意

    给出 n 个点的坐标和它的高度,求一颗生成树使得树上所连边的两点高度差之和除以距离之和最小。

    分析

    01分数规划+最小生成树。
    对于所有的边,在求最小生成树过程中有选或不选的问题,
    首先根据01分数规划,我们要使 $ l = frac{sum_{i=1}^{n} height[i] * exist[i]}{sum_{i=1}^{n} dis[i] * exist[i]}$ (exist[i]表示是否有这条边)最小,
    (F(l) = {sum height[i]*exist[i]}-l*{sum dis[i]*exist[i]}) ,我们要使 (l) 尽可能的小, (F(l))(l) 减小而递增,如果 (F(l) < 0)
    (frac{sum_{i=1}^{n} height[i] * exist[i]}{sum_{i=1}^{n} dis[i] * exist[i]} < l) ,即存在更优的 (l) ,当 (F(l) = 0) 时,即为最终最终答案 (l)
    (D(l) = height[i] - dis[i] * l) ,把它作为边,求最小生成树,那么求得值 (F(l)) 一定是尽可能小的,越有可能出现更优的 (l)

    本题适于采用迭代法,因为在求最小生成树的过程中,就可以计算出更优的 (l) 值。

    code(二分法)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int MAXN = 1e3 + 10;
    const double INF = 1e15;
    int n;
    double dist(double x1, double y1, double x2, double y2) {
        return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }
    struct node {
        double x, y, h;
    }a[MAXN];
    double height[MAXN][MAXN];
    double map[MAXN][MAXN];
    double dis[MAXN];
    int vis[MAXN];
    double prime(double rate) {
        double sum = 0;
        memset(vis, 0, sizeof vis);
        for(int i = 1; i <= n; i++) {
            dis[i] = INF;
        }
        dis[1] = 0;
        for(int i = 0; i < n; i++) {
            double MIN = INF;
            int k;
            for(int j = 1; j <= n; j++) {
                if(!vis[j] && dis[j] < MIN) MIN = dis[k = j];
            }
            vis[k] = 1;
            sum += MIN;
            for(int j = 1; j <= n; j++) {
                if(!vis[j] && dis[j] > height[k][j] - rate * map[k][j]) {
                    dis[j] = height[k][j] - rate * map[k][j];
                }
            }
        }
        return sum;
    }
    void solve() {
        double l = 0, r = 1e5, mid = 0;
        while(r - l > 1e-6) {
            mid = (l + r) / 2;
            if(prime(mid) < 0) r = mid;
            else l = mid;
        }
        printf("%.3f
    ", mid);
    }
    int main() {
        while(cin >> n && n) {
            for(int i = 1; i <= n; i++) {
                cin >> a[i].x >> a[i].y >> a[i].h;
                for(int j = 1; j <= i; j++) {
                    map[i][j] = map[j][i] = dist(a[i].x, a[i].y, a[j].x, a[j].y);
                    height[i][j] = height[j][i] = abs(a[i].h - a[j].h);
                }
            }
            solve();
        }
        return 0;
    }
    

    code(迭代法)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int MAXN = 1e3 + 10;
    const double INF = 1e15;
    int n;
    double dist(double x1, double y1, double x2, double y2) {
        return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }
    struct node {
        double x, y, h;
    }a[MAXN];
    double height[MAXN][MAXN];
    double map[MAXN][MAXN];
    double dis[MAXN];
    int vis[MAXN], pre[MAXN];
    double prime(double rate) {
        double sum = 0;
        double sumh = 0, sumd = 0;
        memset(vis, 0, sizeof vis);
        for(int i = 1; i <= n; i++) {
            dis[i] = INF;
            pre[i] = 0;
        }
        dis[1] = 0;
        for(int i = 0; i < n; i++) {
            double MIN = INF;
            int k;
            for(int j = 1; j <= n; j++) {
                if(!vis[j] && dis[j] < MIN) {
                    MIN = dis[k = j];
                }
            }
            vis[k] = 1;
            sum += MIN;
            sumd += map[pre[k]][k];
            sumh += height[pre[k]][k];
            for(int j = 1; j <= n; j++) {
                if(!vis[j] && dis[j] > height[k][j] - rate * map[k][j]) {
                    dis[j] = height[k][j] - rate * map[k][j];
                    pre[j] = k;
                }
            }
        }
        return sumh / sumd;
    }
    void solve() {
        double k = 0, tmp;
        while(1) {
            tmp = prime(k);
            if(fabs(tmp - k) < 1e-6) break;
            else k = tmp;
        }
        printf("%.3f
    ", k);
    }
    
    int main() {
        while(cin >> n && n) {
            for(int i = 1; i <= n; i++) {
                cin >> a[i].x >> a[i].y >> a[i].h;
                for(int j = 1; j <= i; j++) {
                    map[i][j] = map[j][i] = dist(a[i].x, a[i].y, a[j].x, a[j].y);
                    height[i][j] = height[j][i] = abs(a[i].h - a[j].h);
                }
            }
            solve();
        }
        return 0;
    }
    
  • 相关阅读:
    Spark Streaming:大规模流式数据处理的新贵
    HBase源码学习系列
    Hadoop源码分析之Configuration
    sql server存储引擎启动错误(SQL Server could not spawn FRunCM thread)
    Redis(1.15)Redis监控(待写)
    Redis(1.14)Redis日常管理与维护
    Redis(1.13)Redis cluster 分布式集群手动配置
    (5.3.5)数据库迁移——数据库与文件组的位置迁移(同一实例)
    Redis(1.12)Redis cluster搭建常见错误
    Redis(1.11)Redis4.0.11 cluster 分布式集群搭建
  • 原文地址:https://www.cnblogs.com/ftae/p/6947497.html
Copyright © 2020-2023  润新知