hdu 4009 Transfer water



#include<stdio.h>
#include<string.h>
#define SIZE 1100
#define TYPE int
struct point
{
    int x, y, z;
}node[1010];
struct Edge
{
    int f,t;
    TYPE cost;
}edge[SIZE*SIZE];
int pre[SIZE],id[SIZE],visit[SIZE];//id用来标记圈的
TYPE in[SIZE];//入弧最小的
#define INF 1000000000
bool flag;
int fabs(int x)
{
    if(x < 0)  return -x;
    return x;
}
int dist(point i, point j)
{
    return (fabs(i.x - j.x) + fabs(i.y - j.y) + fabs(i.z - j.z));
}
TYPE DirectedMST(int root,int n,int m)//n表示点数,m表示边数,root表示根
{
    int u,v,i;
    double re=0;
    while(true)
    {
        for(i=1;i<=n;i++)//点号从1开始
            in[i]=INF;
        for(i=0;i<m;i++)
        {
            u=edge[i].f;
            v=edge[i].t;
            if(edge[i].cost<in[v]&&u!=v)
            {
                pre[v]=u;//找出每个点的最小入弧\
                //if(u==root)
                 //   minRoot=i;
                in[v]=edge[i].cost;
            }
        }
        for(i=1;i<=n;i++)
        {
            if(i==root)
                continue;
            if(in[i]==INF){
//除根外有个节点无入弧,就返回false
                flag=false;
                return -1;
            }
        }
        in[root]=0;
        int cnt=1;
        memset(id,-1,sizeof(id));
        memset(visit,-1,sizeof(visit));
        for(i=1;i<=n;i++)
        {
            re+=in[i];//进行缩圈
            v=i;
        while(visit[v]!=i&&id[v]==-1&&v!=root)
            {
                visit[v]=i;
                v=pre[v];
            }
            if(v!=root&&id[v]==-1)
            {
                for(u=pre[v];u!=v;u=pre[u])
                    id[u]=cnt;
                id[v]=cnt++;
            }
        }
        if(cnt==1)
            break;
        for(i=1;i<=n;i++)
        {
            if(id[i]==-1)
                id[i]=cnt++;
        }
        for(i=0;i<m;i++)
        {
            v=edge[i].t;//进行缩点,重新标记。
            edge[i].f=id[edge[i].f];
            edge[i].t=id[edge[i].t];
            if(edge[i].f!=edge[i].t)
                edge[i].cost-=in[v];
        }
        n=cnt-1;
        root=id[root];
    }
    flag=true;
    return re;
}
int main()
{
    int n, m;
    int x, y, z;
    while(scanf("%d%d%d%d", &n, &x, &y, &z) != EOF)
    {
        if(n == 0 && x == 0 && y == 0 && z == 0)  break;

        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].z);
        }

        //n+1为水源
        m = 0;
        for(int i = 1; i <= n; i++)
        {
            edge[m].f = n + 1;
            edge[m].t = i ;
            edge[m].cost = x * node[i].z;
            m++;
        }

        for(int i = 1; i <= n; i++)
        {
            int k, zy;
            int sum;
            scanf("%d", &k);
            for(int j = 1; j <= k; j++)
            {
                scanf("%d", &zy);
                if(zy == i) continue;

                sum = 0;

                if(node[i].z  < node[zy].z) sum += z;//y从i引水
                //printf("%d\n", sum);
                sum += dist(node[i], node[zy]) * y;

                if(sum <= edge[zy-1].cost)
                {
                    edge[m].f = i;
                    edge[m].t = zy;
                    edge[m].cost = sum;
                    //printf("sum=%d\n", sum);
                    m++;
                }
            }
        }

        n++;
        flag = false;
        int re=DirectedMST(n,n,m);
        if(!flag) printf("poor XiaoA\n");
        else printf("%d\n", re);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值