您的位置:首页 > Web前端

[HDU 4009] Transfer water 最小树形图

2015-08-12 19:45 423 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4009

题意:有n个地方需要供水,每个地方都可以选择是自己挖井,还是从别的地方引水,根据方法不同和每个地方的坐标不同,花费也不同,现在给出每个地方的坐标,花费的计算方法,以及每个地方可以给哪些地方供水,求给所有地方供水的最小花费。

思路:建立一个源点,到每个点到源点的距离为自己打井的费用,其他的按条件建边。

[code]#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 1010;
const int inf = (1 << 31) - 1;

struct Point{
    int x, y, z;
};

struct node
{
    int value;
    int in, to;
    node(int a = 0, int b = 0, int c = 0){
        in = a;
        to = b;
        value = c;
    }
};

int cnt;
int in[maxn];
Point point[maxn];
node side[1010000];
int pre[maxn], id[maxn], vis[maxn];

int Mst(int rt, int n, int m)
{
    int sum = 0;
    while(true){
        for(int i = 0; i < n; i++){
            in[i] = inf;
        }
        for(int i = 0; i < m; i++)  //找最小入边
        {
            int x = side[i].to;
            if(in[x] > side[i].value && x != side[i].in){
                in[x] = side[i].value;
                pre[x] = side[i].in;
            }
        }
        for(int i = 0; i < n; i++){  //判断除了根是否还有其他入度为0的点
            if(i != rt && in[i] == inf)  //不存在
                return -1;
        }
        cnt = in[rt] = 0;
        memset(id, -1, sizeof(id));
        memset(vis, -1, sizeof(vis));
        for(int i = 0; i < n; i++){
            sum += in[i];
            int x = i;
            while(vis[x] != i && x != rt && id[x] == -1){  //找环
                vis[x] = i;
                x = pre[x];
            }
            if(id[x] == -1 && x != rt){
                int y = pre[x];
                while(x != y){  //给环重新编号
                    id[y] = cnt;
                    y = pre[y];
                }
                id[x] = cnt++;
            }
        }
        if(cnt == 0)
            break;
        for(int i = 0; i < n; i++){
            if(id[i] == -1)
                id[i] = cnt++;
        }
        for(int i = 0; i < m; i++){  //压环成点
            int x = side[i].to;
            side[i].in = id[side[i].in];
            side[i].to = id[side[i].to];
            if(side[i].in  != side[i].to)
                side[i].value -= in[x];
        }
        n = cnt;
        rt = id[rt];
    }
    return sum;
}

int length(Point a, Point b)
{
    return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
}

int main()
{
    int n, x, y, z;
    while(~scanf("%d%d%d%d",&n,&x,&y,&z) && (n || x || y || z))
    {
        int top = 0;
        for(int i = 1 ;i <= n;i++)
        {
            scanf("%d%d%d",&point[i].x, &point[i].y, &point[i].z);
            side[top++] = node(0, i, x * point[i].z);
        }
        int k, w;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &k);
            while(k--){
                scanf("%d", &w);
                if(i == w)
                    continue;
                int len = length(point[i], point[w]);
                if(point[i].z >= point[w].z)
                    side[top++] = node(i, w, len * y);
                else
                    side[top++] = node(i, w, len * y + z);
            }
        }
        printf("%d\n", Mst(0, n+1, top));
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: