CUGB图论专场:J - Transfer water(最小树形图)

J - Transfer water
Time Limit:3000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64u
Submit  Status

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 30 1 3 2 2 4 1 1 2 2 1 2 0 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|. 
 

这题和D题都是最小树形图,主要会处理数据,把所有的边的可能加入树形图,然后求出最小值。在输入数据处理的时候刚开始处理得不好,T了几发,然后改用初始化列表水过了,虽然还是1587ms这么多的时间……

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define M 1002
#define INF 10000000
using namespace std;
typedef long long ll;
struct node
{
    int u,v,w;   //边的两端结点
    node() {}
    node(int u1,int v1,int w1):u(u1),v(v1),w(w1) {} //初始化值值列表
}e[M*M];
int pre[M],newnode[M],in[M],visit[M],a[M],b[M],c[M],n,t; //前向结点数组,新结点指向数组,边权值数组,访问数组
inline int dist(int i,int j)  //坐标两点之间的距离
{
    return abs(a[i]-a[j])+abs(b[i]-b[j])+abs(c[i]-c[j]);
}
int zhuliu(int root)
{
    int u,v,i,ans=0;  //因为把环删除后其边权值是当前和与原先和之和,所以得在循环外定义
    n++;
    while(1)
    {
        //(1).找最小边放入集合
        for(i=0;i<n;i++)
            in[i]=INF;
        for(i=0;i<t;i++)
        {
            u=e[i].u; v=e[i].v;
            if(e[i].w<in[v]&&u!=v)
            {
                pre[v]=u;  //每次都找最小边进入集合,以达最优解
                in[v]=e[i].w;
            }
        }
        in[root]=0;
        for(i=0;i<n;i++)
            if(in[i]==INF) return -1; //除了根以外还有别的结点没有入边,则说明没有连通,无最小树形图
        //(2).找环,若有环,则生成新结点,强连通分量,即环
        int New=0; //新结点还是从0开始
        mem(newnode,-1);
        mem(visit,-1);
        for(i=0;i<n;i++)  //寻找每个结点是否有环
        {
            ans+=in[i]; v=i;
            while(visit[v]!=i&&newnode[v]==-1&&v!=root) //每个点寻找其前向点,要么最终寻找至根部,要么找到一个环
            {
                visit[v]=i;
                v=pre[v];
            }
            if(v!=root&&newnode[v]==-1)  //把环缩成一个点,缩点法
            {
                for(u=pre[v];u!=v;u=pre[u])
                    newnode[u]=New;
                newnode[v]=New++;
            }
        }
        if(New==0) break;  //如果New无变化,当然就无环啦
        for(i=0;i<n;i++)
            if(newnode[i]==-1) newnode[i]=New++;
        //(3).建立新图,即把环缩成点,然后指向和边权值也随之改变
        for(i=0;i<t;i++)
        {
            u=e[i].u; v=e[i].v;
            e[i].u=newnode[u];
            e[i].v=newnode[v];
            if(newnode[u]!=newnode[v]) e[i].w-=in[v]; //两个不同的结点之间的边权值改变
        }
        n=New;
        root=newnode[root];  //结点更新之后,根结点可能有环而改变,所以根结点也要更新
    }
    return ans;
}
int main()
{
    int i,j,x,y,z,m,ab; //把所有可能的结点与边都加入最小树形图中
    while(scanf("%d%d%d%d",&n,&x,&y,&z)&&(n||x||y||z))
    {
        for(i=1,t=0;i<=n;i++) //结点从1开始
        {
            scanf("%d%d%d",&a[i],&b[i],&c[i]);
            e[t++]=node(0,i,c[i]*x);
        }
        for(i=1;i<=n;i++)
        {
            for(j=0,sca(m);j<m;j++)
            {
                sca(ab);
                if(ab==i) continue;  //下一句:结点从1开始
                int d=dist(i,ab)*y;
                e[t++]=(c[i]>=c[ab]?node(i,ab,d):node(i,ab,d+z));
            }
        }
        int ans=zhuliu(0);
        ans==-1?printf("poor XiaoA\n"):pri(ans);
    }
    return 0;
}


你可能感兴趣的:(CUGB图论专场:J - Transfer water(最小树形图))