• HDU


    题目大意:有N个点。每一个点都有对应的三维坐标(x,y,z)
    如今要求每一个点都能获得水,或者水的方式有两种
    1.自己挖井,费用为X * 海拔高度z
    2.铺设管道引水。
    a.假设海拔高度小于引水处。费用为两地曼哈顿距离*Y
    b.假设海拔高度大于饮水处。费用为两地曼哈顿距离*Y + Z

    解题思路:设置一个虚根。虚根引向全部的点,权值为挖井的费用,接着依照要求连边,求出最小树形图就可以

    #include <cstdio>
    #include <cstring>
    
    #define N 1010
    #define abs(a) ((a)>0?(a):(-(a)))
    
    struct Edge{
        int u, v, c;
    }E[N*N];
    
    struct Point{
        int x, y, z;
    }P[N];
    
    int n, x, y, z, tot;
    
    void AddEdge(int u, int v, int c) {
        E[tot].u = u; E[tot].v = v; E[tot++].c = c;
    }
    
    void init() {
        tot = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d%d%d", &P[i].x, &P[i].y, &P[i].z);
            AddEdge(0, i, P[i].z * x);
        }
    
        int k, t;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &k);
            while (k--) {
                scanf("%d", &t);
                if (t == i)
                    continue;
                if (P[i].z >= P[t].z) {
                    int dis = abs(P[t].x - P[i].x) + abs(P[t].y - P[i].y) + abs(P[t].z - P[i].z);
                    AddEdge(i, t, dis * y);
                }
                else {
                    int dis = abs(P[t].x - P[i].x) + abs(P[t].y - P[i].y) + abs(P[t].z - P[i].z);
                    AddEdge(i, t, dis * y + z);
                }
            }
        }
    }
    
    #define INF 0x3f3f3f3f
    int in[N], pre[N], vis[N], id[N];
    int Directed_MST(int root, int n) {
        int ans = 0, u, v, tmp;
        while (1) {
            for (int i = 0; i < n; i++)
                in[i] = INF;
            for (int i = 0; i < tot; i++) {
                u = E[i].u;
                v = E[i].v;
                if (u != v && E[i].c < in[v]) {
                    in[v] = E[i].c;
                    pre[v] = u;
                }
            }
            memset(vis, -1, sizeof(vis));
            memset(id, -1, sizeof(id));
            in[root] = 0;
            int subnode = 0;
            for (int i = 0; i < n; i++) {
                ans += in[i];
                tmp = i;
                while (vis[tmp] != i && tmp != root && id[tmp] == -1) {
                    vis[tmp] = i;
                    tmp = pre[tmp];
                }
                if (id[tmp] == -1 && tmp != root) {
                    u = pre[tmp];
                    while (u != tmp) {
                        id[u] = subnode;
                        u = pre[u];
                    }
                    id[tmp] = subnode++;
                }
            }
    
            if (subnode == 0)
                break;
            for (int i = 0; i < n; i++)
                if (!(~id[i]))
                    id[i] = subnode++;
            for (int i = 0; i < tot; i++) {
                tmp = E[i].v;
                E[i].u = id[E[i].u];
                E[i].v = id[E[i].v];
    
                if (E[i].u != E[i].v)
                    E[i].c -= in[tmp];
            }
            n = subnode;
            root = id[root];
        }
        return ans;
    }
    
    void solve() {
        n++;
        int ans = Directed_MST(0,n);
        if (ans == -1) 
            printf("poor XiaoA
    ");
        else
            printf("%d
    ", ans);
    }
    
    int main() {
        while (scanf("%d%d%d%d", &n, &x, &y, &z) != EOF && n + x + y + z) {
            init();
            solve();
        }
        return 0;
    }
    
  • 相关阅读:
    7-1 N个数求和
    3662. 最大上升子序列和
    树状数组
    堆优化Dijkstra java模板
    皮亚诺曲线距离
    最长公共子序列(计数问题)
    最小路径覆盖
    极角排序
    2619. 询问
    Hessian矩阵与局部极小值
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/7353334.html
Copyright © 2020-2023  润新知