hdu4009 Transfer water(最小树形图模板)

题目链接:点击打开链接

题意描述:在一个村庄有n户人家(x,y,h),现在打算在村庄中挖井和建水渠使每户人家都可以用上水

1、如果挖井费用为高度h*X;

2、如果a->b建水渠,if(a.h>=b.h)费用为两点距离dis*Y,反之费用为dis*Y+Z

问,怎样挖井和建水渠才能使费用最小?


解体思路:最小树形图:点击打开链接

分析:我们可以新建一个源点指向所有的用户,权值为挖井的费用,然后根据是否能建水渠构建个用户之间的关系,求图的最小树形图即可

代码:

#include 
#include 
#include 
#include 
#define MAXN 1010
#define INF 0x7fffffff
using namespace std;
struct Point{
    int x,y,z;
}p[MAXN];
struct Edge{
    int u,v,cost;
    Edge(){}
    Edge(int u,int v,int cost):u(u),v(v),cost(cost){}
}edge[MAXN*MAXN];
int n,m,X,Y,Z;
inline int get_cost(Point a,Point b){
    int dis=abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z);
    if(a.z>=b.z) return dis*Y;
    return dis*Y+Z;

}
int pre[MAXN];///记录当前顶点的前驱顶点
int id[MAXN];///经过缩点之后:原图顶点号->新图顶点号
int in[MAXN];///记录顶点所有入边的权值的最小值
int vis[MAXN];///是否访问过当前顶点
inline int ZhuLiu(int root,int n,int m){
    int u,v;
    int ret=0;///最小树形图的权值
    while(true){
        for(int i=0;i<=n;++i) in[i]=INF;
        /*记录顶点所有入边的权值的最小值*/
        for(int i=0;iv这种入边
                pre[v]=u;
                in[v]=edge[i].cost;
            }
        }
        /*除根节点外其他顶点每个点都必须有入边,如果没有则无法构成树,返回INF表示不存在*/
        for(int i=0;i<=n;++i){
            if(i==root) continue;
            if(in[i]==INF) return INF;
        }
        in[root]=0;
        int cnt=0;///对每个顶点进行重新编号
        memset(id,-1,sizeof(id));
        memset(vis,-1,sizeof(vis));
        for(int i=0;i<=n;++i){
            ret+=in[i];
            v=i;
            /*构造环*/
            while(vis[v]!=i&&id[v]==-1&&v!=root){
                vis[v]=i;
                v=pre[v];
            }
            /*判断是否存在环,如果存在环则进行缩点,环中每一个顶点对应同一个顶点cnt*/
            if(v!=root&&id[v]==-1){
                for(u=pre[v];u!=v;u=pre[u]) id[u]=cnt;
                id[v]=cnt++;
            }
        }
        /*如果不存在环,则当前树即为最小树形图*/
        if(cnt==0) break;
        /*对于其他不在环中的顶点进行编号*/
        for(int i=0;i<=n;++i){
            if(id[i]==-1) id[i]=cnt++;
        }
        /*对相应的边进行修改*/
        for(int i=0;i


你可能感兴趣的:(图论,模板)