[HDU 4009] Transfer water 最小树形图

来源:互联网 发布:淘宝全球购认证商家 编辑:程序博客网 时间:2024/06/05 14:21

http://acm.hdu.edu.cn/showproblem.php?pid=4009

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

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

#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;}
0 0
原创粉丝点击