zoukankan      html  css  js  c++  java
  • hdu 4009 最小树形图

    思路:唯一一个值得一提的就是建一个0号根节点,往每个房子建一条边,权值为房子的高度乘以X。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define Maxn 1010
    #define Maxm Maxn*Maxn
    #define inf 100000000
    using namespace std;
    int head[Maxn],vi[Maxn],id[Maxn],in[Maxn],pre[Maxn],cnt,X,Y,Z,n,e;
    struct Edge{
        int u,v,next,val;
    }edge[Maxm];
    struct Point{
        int x,y,z;
    }p[Maxn];
    void init()
    {
        memset(head,-1,sizeof(head));
        e=0;
    }
    void add(int u,int v,int val)
    {
        edge[e].u=u,edge[e].v=v,edge[e].val=val,edge[e].next=head[u],head[u]=e++;
    }
    int Dis(Point a,Point b)
    {
        return abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z);
    }
    int directed_MST(int root,int N,int E)
    {
        int ans=0,i,j,u,v;
        while(1)
        {
            for(i=0;i<N;i++)
                in[i]=inf;
            for(i=0;i<E;i++)
            {
                u=edge[i].u,v=edge[i].v;
                if(in[v]>edge[i].val&&u!=v)
                {
                    pre[v]=u;
                    in[v]=edge[i].val;
                }
            }
            for(i=0;i<N;i++)
            {
                if(i==root) continue;
                if(in[i]==inf) return -1;
            }
            memset(vi,-1,sizeof(vi));
            memset(id,-1,sizeof(id));
            cnt=0;
            in[root]=0;
            for(i=0;i<N;i++)//枚举每个可能是环上的点
            {
                ans+=in[i];
                v=i;
                while(vi[v]!=i&&id[v]==-1&&v!=root)
                {
                    vi[v]=i;v=pre[v];
                }
                if(v!=root&&id[v]==-1)//如果退出上个循环的条件不是v==root,就是vi[i]==i,即找到了环
                {
                    for(u=pre[v];u!=v;u=pre[u])//对环进行统一标号
                        id[u]=cnt;
                        id[v]=cnt++;
                }
            }
            if(cnt==0) break;//无环 ,退出
            for(i=0;i<N;i++) if(id[i]==-1) id[i]=cnt++;
            for(i=0;i<E;i++)//进行缩点,并修改每条边的权值。
            {
                v=edge[i].v;
                edge[i].u=id[edge[i].u];
                edge[i].v=id[edge[i].v];
                if(edge[i].u!=edge[i].v)
                    edge[i].val-=in[v];
            }
            N=cnt;
            root=id[root];
        }
        return ans;
    }
    int main()
    {
        int i,j,a,b,c,k;
        while(scanf("%d%d%d%d",&n,&X,&Y,&Z),n|X|Y|Z)
        {
            init();
            for(i=1;i<=n;i++)
                scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
            for(i=1;i<=n;i++)
            {
                scanf("%d",&k);
                for(j=1;j<=k;j++)
                {
                    scanf("%d",&a);
                    if(a==i) continue;
                    if(p[a].z>p[i].z)
                        add(i,a,Dis(p[a],p[i])*Y+Z);
                    else
                        add(i,a,Dis(p[a],p[i])*Y);
                }
            }
            for(i=1;i<=n;i++)
                add(0,i,X*p[i].z);
            printf("%d
    ",directed_MST(0,n+1,e));
        }
        return 0;
    }
  • 相关阅读:
    Linux线程同步方法
    Linux进程间通信:信号
    孤儿进程僵尸进程及其回收
    Linux守护进程
    Linux系统编程常见函数 (进程/线程)
    Linux系统编程常用函数 (文件/目录)
    C++实现贪吃蛇小游戏
    C++实现简易Vector类
    C++实现简易版字符串类
    《图解HTTP》读书笔记
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3221271.html
Copyright © 2011-2022 走看看