Transfer water HDU - 4009 最小树形图

本文探讨了一个关于N个三维坐标点的供水问题,提出了两种供水方式:自行挖井和铺设管道引水,并详细介绍了使用最大流算法解决该问题的具体实现过程。

题目大意:有N个点,每个点都有相应的三维坐标(x,y,z)
现在要求每个点都能获得水,或者水的方式有两种
1.自己挖井,费用为X * 海拔高度z
2.铺设管道引水。
a.如果海拔高度小于引水处,费用为两地曼哈顿距离*Y
b.如果海拔高度大于饮水处,费用为两地曼哈顿距离*Y + Z

这代码还是挺好看的。。
https://vjudge.net/solution/3198132
就按照他的模板。

越看越像用 最大流的模板一样。。
https://vjudge.net/contest/179107#problem/A

int x[mxn],y[mxn],z[mxn];
int X,Y,Z;
int n,m;
int pre[mxn],id[mxn],vis[mxn],in[mxn];
struct edge{
    int u,v,c;
    void getE(int i,int j){
        u=i,v=j;
        c=abs(x[i]-x[j])+abs(y[i]-y[j])+abs(z[i]-z[j]);
        c*=Y;
        if(z[j]>z[i])
            c+=Z;
    }
}e[mxe];

int DMST(int s,int n){
    int ret=0;
    while(1){
        mem(in,inf);
        for(int i=1;i<=m;++i){
            int u=e[i].u,v=e[i].v,c=e[i].c;
            if(c<in[v]&u!=v){
                pre[v]=u,in[v]=c;
            }
        }
        for(int i=1;i<=n;++i)
            if(in[i]==inf&&i!=s)
                return -1;
        in[s]=0;
        int cnt=0;
        mem(id,-1);
        mem(vis,-1);
        for(int i=1;i<=n;++i){
            ret+=in[i];
            int v=i;
            while(vis[v]!=i&&id[v]==-1&&v!=s)
                vis[v]=i,v=pre[v];
            if(id[v]==-1&&v!=s){//处理环的地方
                id[v]=++cnt;
                for(int u=pre[v];u!=v;u=pre[u])
                    id[u]=cnt;
            }
        }
        if(cnt==0)break;//没有环就退出
        for(int i=1;i<=n;++i)if(id[i]==-1)id[i]=++cnt;
        for(int i=1;i<=m;++i){
            int u=e[i].u,v=e[i].v;
            e[i].u=id[u],e[i].v=id[v];
            if(id[u]!=id[v])
                e[i].c-=in[v];
            }
        n=cnt;
        s=id[s];
    }
    return ret;
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~sf("%d%d%d%d",&n,&X,&Y,&Z)&&n){
        rep(i,1,n)sf("%d%d%d",&x[i],&y[i],&z[i]);
        m=0;
        for(int i=1;i<=n;++i){
            int k;
            sf("%d",&k);
            while(k--){
                int v;sf("%d",&v);
                if(v==i)continue;
                e[++m].getE(i,v);
            }
        }
        for(int i=1;i<=n;++i){
            ++m;
            e[m].u=n+1,e[m].v=i;
            e[m].c=abs(z[i])*X;
        }
        int ans=DMST(n+1,n+1);
        if(ans==-1)
            puts("poor XiaoA");
        else pf("%d\n",ans);
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值