zoukankan      html  css  js  c++  java
  • HDU 4009 Transfer water(最小树形图)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4009

    题意:给出一个村庄(x,y,z)。每个村庄可以挖井或者修建水渠从其他村庄得到水。挖井有一个代价,修水渠有一个代价。另外A村庄只能向其指定的一些村庄供水。使得所有村庄有水求最小代价。

    思路:增加虚拟点0,向所有点连边表示挖井。能连边的连边。求最小树形图即可。

    struct point
    {
        int x,y,z;
    };
    
    struct edge
    {
        int u,v,w;
    };
    
    point p[N];
    edge e[N*N];
    int eCnt,n,pre[N],id[N],in[N],visit[N];
    
    
    void add(int u,int v,int w)
    {
        e[eCnt].u=u;
        e[eCnt].v=v;
        e[eCnt++].w=w;
    }
    
    int directedMST(int root)
    {
        int ans=0,nv=n,i;
        while(1)
        {
            for(i=0;i<nv;i++) in[i]=INF;
            for(i=0;i<eCnt;i++)
            {
                int u=e[i].u;
                int v=e[i].v;
                if(u!=v&&e[i].w<in[v])
                {
                    in[v]=e[i].w;
                    pre[v]=u;
                }
            }
            for(i=0;i<nv;i++)
            {
                if(i!=root&&inf==in[i]) return -1;
            }
            int nodeCnt=0;
            for(i=0;i<nv;i++) id[i]=visit[i]=-1;
            in[root]=0;
            for(i=0;i<nv;i++)
            {
                ans+=in[i];
                int v=i;
                while(visit[v]!=i&&id[v]==-1&&v!=root)
                {
                    visit[v]=i;
                    v=pre[v];
                }
                if(v!=root&&-1==id[v])
                {
                    int u;
                    for(u=pre[v];u!=v;u=pre[u]) id[u]=nodeCnt;
                    id[v]=nodeCnt++;
                }
            }
            if(0==nodeCnt) break;
            for(i=0;i<nv;i++) if(-1==id[i]) id[i]=nodeCnt++;
            for(i=0;i<eCnt;i++)
            {
                int v=e[i].v;
                e[i].u=id[e[i].u];
                e[i].v=id[e[i].v];
                if(e[i].u!=e[i].v) e[i].w-=in[v];
            }
            nv=nodeCnt;
            root=id[root];
        }
        return ans;
    }
    
    
    int X,Y,Z;
    
    int Dis(point a,point b)
    {
        int dis=abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z);
        dis*=Y;
        if(a.z<b.z) dis+=Z;
        return dis;
    }
    
    int main()
    {
    	while(scanf("%d%d%d%d",&n,&X,&Y,&Z)!=EOF)
    	{
    	    if(!n&&!X&&!Y&&!Z) break;
    		int i,j,u,v;
    		n++;
    		for(i=1;i<n;i++) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
            eCnt=0;
    		for(i=1;i<n;i++)
    		{
    		    int k;
    		    scanf("%d",&k);
    		    while(k--)
    		    {
    		        int t;
    		        scanf("%d",&t);
    		        if(t==i) continue;
    		        add(i,t,Dis(p[i],p[t]));
    		    }
    		    add(0,i,p[i].z*X);
    		}
    		printf("%d
    ",directedMST(0));
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何使用Apache设置404页面
    字符串函数积累
    isset() unset()
    set_exception_handler 自定义异常处理
    phpMailer中文说明[转]
    我的PHPMailer_v5.1 使用
    PHPMailer_v5.1 使用[转]
    PHP错误和异常处理
    几个 PHP 的“魔术常量”
    九宫格布局(demo16.03.14)
  • 原文地址:https://www.cnblogs.com/twodog/p/12135291.html
Copyright © 2011-2022 走看看