HDU4009 Transfer water [最小树形图]

  最小树形图模版题,学习了一下最小树形图。

  三步走,找最小入弧,找有向环,缩环为点。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define INF 0x3f3f3f3f
#define MAXN 1001
struct edge{
    int u,v,w;
}e[MAXN*MAXN];
int n,x,y,z,es,k,tt;
int pnt[MAXN][3];
int dist(int p1,int p2){
    int ret=0;
    for(int i=0;i<3;i++)ret+=abs(pnt[p1][i]-pnt[p2][i]);
    return ret;
}
void addedge(int u,int v,int w){
    e[es].u=u,e[es].v=v,e[es].w=w,es++;
}
/*点和边都是从0开始的,root包含在点集中*/
int in[MAXN],pre[MAXN],id[MAXN],vis[MAXN];
int dir_mst(int root,int vs,int es){
    int ret=0;
    for(;;){
        int size=vs*4;
        memset(in,0x3f,size);
        memset(id,-1,size);
        memset(vis,-1,size);
        //step1:找最小入弧
        for(int i=0;i<es;i++){
            int u=e[i].u,v=e[i].v,w=e[i].w;
            if(w>=in[v]||u==v)continue;
            pre[v]=u,in[v]=w;
        }
        in[root]=0,pre[root]=root;
            //如果有孤立点说明无解
        for(int i=0;i<vs;i++){
            ret+=in[i];
            if(in[i]==INF)return -1;
        }
        //step2:找有向环
        int idx=0;
        for(int i=0;i<vs;i++)if(vis[i]==-1){
            int u=i;
            while(vis[u]==-1)vis[u]=i,u=pre[u];
            if(vis[u]!=i||u==root)continue;
            for(int t=pre[u];t!=u;t=pre[t])id[t]=idx;
            id[u]=idx++;
        }
            //没有环,已经完成
        if(idx==0)break;
        for(int i=0;i<vs;i++)if(id[i]==-1)id[i]=idx++;
        //step3:将环缩为点
        for(int i=0;i<es;i++){
            e[i].w-=in[e[i].v];
            e[i].u=id[e[i].u];
            e[i].v=id[e[i].v];
        }
        vs=idx;
        root=id[root];
    }
    return ret;
}
int main(){
    freopen("test.in","r",stdin);
    while(scanf("%d%d%d%d",&n,&x,&y,&z),n||x||y||z){
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&pnt[i][0],&pnt[i][1],&pnt[i][2]);
        es=0;
        for(int i=1;i<=n;i++)
            addedge(0,i,pnt[i][2]*x);
        for(int i=1;i<=n;i++){
            scanf("%d",&k);
            while(k--){
                scanf("%d",&tt);
                if(pnt[i][2]>=pnt[tt][2])addedge(i,tt,dist(i,tt)*y);
                else addedge(i,tt,dist(i,tt)*y+z);
            }
        }
        int res=dir_mst(0,n+1,es);
        if(res==-1)printf("poor XiaoA\n");
        else printf("%d\n",res);
    }
}
posted @ 2012-08-27 22:15  Burn_E  阅读(216)  评论(0编辑  收藏  举报