HDU 4009:Transfer water

来源:互联网 发布:网页淘宝自动跳转app 编辑:程序博客网 时间:2024/05/22 17:42


Transfer water

Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 5171    Accepted Submission(s): 1860


Problem Description
XiaoA lives in a village. Last year flood rained the village. So they decide to move the whole village to the mountain nearby this year. There is no spring in the mountain, so each household could only dig a well or build a water line from other household. If the household decide to dig a well, the money for the well is the height of their house multiplies X dollar per meter. If the household decide to build a water line from other household, and if the height of which supply water is not lower than the one which get water, the money of one water line is the Manhattan distance of the two households multiplies Y dollar per meter. Or if the height of which supply water is lower than the one which get water, a water pump is needed except the water line. Z dollar should be paid for one water pump. In addition,therelation of the households must be considered. Some households may do not allow some other households build a water line from there house. Now given the 3‐dimensional position (a, b, c) of every household the c of which means height, can you calculate the minimal money the whole village need so that every household has water, or tell the leader if it can’t be done.
 

Input
Multiple cases. 
First line of each case contains 4 integers n (1<=n<=1000), the number of the households, X (1<=X<=1000), Y (1<=Y<=1000), Z (1<=Z<=1000). 
Each of the next n lines contains 3 integers a, b, c means the position of the i‐th households, none of them will exceeded 1000. 
Then next n lines describe the relation between the households. The n+i+1‐th line describes the relation of the i‐th household. The line will begin with an integer k, and the next k integers are the household numbers that can build a water line from the i‐th household. 
If n=X=Y=Z=0, the input ends, and no output for that. 
 

Output
One integer in one line for each case, the minimal money the whole village need so that every household has water. If the plan does not exist, print “poor XiaoA” in one line. 
 

Sample Input
2 10 20 301 3 22 4 11 22 1 20 0 0 0
 

Sample Output
30
Hint
In 3‐dimensional space Manhattan distance of point A (x1, y1, z1) and B(x2, y2, z2) is |x2‐x1|+|y2‐y1|+|z2‐z1|.

题目翻译:

问题描述:
小A住在一个村庄,去年洪水淹没了这个村庄。因此他们决定将整个村庄搬到附近的山上。山上没有泉水,因此每一家必须选择打一个井或者从别的人家引水。如果一家决定去挖一口井,则他们打井的费用是他们房子的高度,X每米。如果决定去引水,如果引水的地方比当前地方高,则引水的钱是这两家的距离成上Y美元每米。如果引水的地方比当前低。则必须需要水泵(除了引水线后)还要花费Z美元买一个水泵。除此之外,村民的关系是需要考虑的。一些村民不允许一些村民从他们的房子引水。现在给出3个实数(a,b,c)。每个房子的坐标。计算整个村庄都通上水的最小花费。如果不能,则输出不能。
输入:
多组测试数据.
第一行包含四个整数,n(家庭个数),X(自己选择打井每米的费用),Y(从高处往低处引水,Y美元每米),Z(一个水磅的价钱)。
接下来是N行,每行三个整数a,b,c,代表第i个房子的位置。
接下来N行,描述这些村民的关系。每行一个整数t,然后后面t个整数代表这t个节点都能从节点i引水。
题目规定这个三维空间两点的距离这样计算
Point A(x1,y1,z1)和 Point B(x2,y2,z2) 的距离这样算
abs(x1-x2)+abs(y1-y2)+abs(z1-z2)
输出:
如果能满足每户人家都能通上水,输出最小花费,否则输出
poor XiaoA


解题思路:

非常好的一道题目,用的还是朱刘算法求最小树形图。只存储边的关系。

因为每个节点可以考虑自己打井,也可以考虑从其他村民家引水,因此在哪里打井都不确定。这里有一个很巧妙的方法创建一个人工节点0,代表我在这个地方挖井不要钱。

然后我将0到其他节点的权值赋为在每个节点打井的费用。这一点思想和第八届河南省省赛题目:引水工程  求最小生成树的处理方法是一样的。

如果节点 i 能从节点 j 引水。如果节点 j 比节点 i 的高度低,则引水除了线路铺设费用,还要加上买水泵的钱。

建立图后。用以0为定跟,用朱刘算法求最小树形图即可。


#include <iostream>#include <string.h>#include <cstdio>#include <cmath>#define INF 0x3f3f3f3fusing namespace std;const int maxn = 1004;int N,X,Y,Z;///N是节点个数,X是每个家庭选择自己打井每米的费用。///Y是从别人家引水每米的费用,Z是一台水泵的价钱(从低处往高处引水要用水泵)struct pos    ///每个村民家的三维坐标{    int x;    int y;    int z;}p[maxn];struct Edge{    int u;    int v;    long long int w;}edge[maxn*maxn];long long int Distance(struct pos p1,struct pos p2)  ///题目定义三维两点距离这样计算{    return abs(p1.x-p2.x)+abs(p1.y-p2.y)+abs(p1.z-p2.z);}int closest[maxn],id[maxn],vis[maxn],in[maxn];long long int Min_Cost(int root,int NodeNum,int EdgeNum){    long long int ans = 0;    int i;    while(true)    {        ///1.求每个节点的最小入边权值        for(i = 0; i < NodeNum; i++) ///节点编号从0~N,总共N+1个点            in[i] = INF;        for(i = 0; i < EdgeNum; i++)        {            int u = edge[i].u;            int v = edge[i].v;            if(u!=v && edge[i].w < in[v])            {                in[v] = edge[i].w;                closest[v] = u;            }        }        for(i = 0; i < NodeNum; i++)        {            if(i == root) continue;            if(in[i]==INF) return -1;        }        ///2.判断有无环。        int CNT = 0;        memset(vis,-1,sizeof(vis));        memset(id,-1,sizeof(id));        in[root] = 0;        for(i = 0; i < NodeNum; i++)        {            ans += in[i];            int v = i;            while(v != root && vis[v]!=i && id[v]==-1)            {                vis[v] = i;                v = closest[v];            }            if(v != root && id[v]==-1)            {                for(int u = closest[v]; u != v; u = closest[u])                {                    id[u] = CNT;                }                id[v] = CNT++;            }        }        if(CNT == 0) break;        for(i = 0; i < NodeNum; i++)        {            if(id[i]==-1)                id[i] = CNT++;        }        ///更新图        for(i = 0; i < EdgeNum; i++)        {            int u = edge[i].u;            int v = edge[i].v;            edge[i].u = id[u];            edge[i].v = id[v];            if(id[u] != id[v])                edge[i].w = edge[i].w - in[v];        }        NodeNum = CNT;        root = id[root];    }    return ans;}int main(){    int t,node;    while(~scanf("%d%d%d%d",&N,&X,&Y,&Z))    {        if(N == 0 && X == 0 && Y == 0 && Z == 0) break;        for(int i = 1; i <= N; i++)  ///输入N个村民家的坐标            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);        int k = 0;        ///建立虚拟节点0,0到其他节点引水的权值是每个地方的打井费用        for(int i = 1; i <= N; i++)        {            edge[k].u = 0;            edge[k].v = i;            edge[k].w = X*p[i].z;            k++;        }        for(int i = 1; i <= N; i++)        {            scanf("%d",&t);  ///能从第i个村民家引水的家庭有t个            for(int j = 1; j <= t; j++)            {                scanf("%d",&node);                edge[k].u = i;                edge[k].v = node;                edge[k].w = Distance(p[i],p[node])*Y;                if(p[i].z < p[node].z)  ///如果节点i比节点z的高度低,要买水泵                    edge[k].w += Z;                k++;            }        }        long long int ans = Min_Cost(0,N+1,k);        if(ans < INF)            printf("%lld\n",ans);        else            printf("poor XiaoA\n");    }    return 0;}



0 0