HDOJ 4009-Transfer water最小树形图解题报告
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4009
这道题是说一个村庄里的人家住在不同的位置,而且有不同的高度,每户人家可以自己修建水井,也可以选择从别的人家修建引水渠,并且回因为位置的高低产生不同的费用,首先,每户人家都可以选择自己修建水井,所以不存在无解的情况,然后,建立一个虚拟根,从根出发到第i个节点有权值为这户人家自己修建水井的费用,如果i能从j引水,从j到i建立一条权值为修建引水渠费用的边,最后要找的就是这个有向图的最小树形图。关于最小树形图百度百科有详细的描述和算法介绍,可以参照代码进行比对。
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define N 1005 5 #define inf 0x7fffffff 6 using namespace std; 7 struct point 8 { 9 int x,y,z; 10 }; 11 int Abs(int a) 12 { 13 return a<0?-a:a; 14 } 15 point p[N]; 16 int dis(point p1,point p2) 17 { 18 return Abs(p1.x-p2.x)+Abs(p1.y-p2.y)+Abs(p1.z-p2.z); 19 } 20 int cnt; 21 struct node 22 { 23 int u,v,w; 24 }; 25 node e[N*N]; 26 int n,id[N],vis[N],pre[N],in[N]; 27 void init() 28 { 29 cnt=0; 30 } 31 void add(int u,int v,int w) 32 { 33 e[cnt].u=u,e[cnt].v=v,e[cnt++].w=w; 34 } 35 int directedMST(int root) 36 { 37 int res=0,cntnode,nv=n; 38 int i,j,k,u,v; 39 while(1) 40 { 41 for(i=0;i<nv;i++) 42 { 43 in[i]=inf; 44 } 45 for(i=0;i<cnt;i++) 46 { 47 u=e[i].u; 48 v=e[i].v; 49 if(in[v]>e[i].w&&u!=v) 50 { 51 pre[v]=u; 52 in[v]=e[i].w; 53 } 54 } 55 for(i=0;i<nv;i++) 56 { 57 if(i==root) 58 continue; 59 if(in[i]==inf) 60 return -1; 61 } 62 in[root]=0; 63 memset(id,-1,sizeof(id)); 64 memset(vis,-1,sizeof(vis)); 65 cntnode=0; 66 for(i=0;i<nv;i++) 67 { 68 res+=in[i]; 69 v=i; 70 while(vis[v]!=i&&id[v]==-1&&v!=root)//找自环 71 { 72 vis[v]=i; 73 v=pre[v]; 74 } 75 if(v!=root&&id[v]==-1)//缩点 76 { 77 for(u=pre[v];u!=v;u=pre[u]) 78 id[u]=cntnode; 79 id[v]=cntnode++; 80 } 81 } 82 if(cntnode==0) 83 break; 84 for(i=0;i<nv;i++) 85 if(id[i]==-1) 86 id[i]=cntnode++; 87 for(i=0;i<cnt;i++) 88 { 89 v=e[i].v; 90 e[i].u=id[e[i].u]; 91 e[i].v=id[e[i].v]; 92 if(e[i].u!=e[i].v) 93 e[i].w-=in[v]; 94 } 95 nv=cntnode; 96 root=id[root]; 97 } 98 return res; 99 } 100 int main() 101 { 102 int X,Y,Z,u,v,i,j,k,cost; 103 while(scanf("%d%d%d%d",&n,&X,&Y,&Z)&&(n||X||Y||Z)) 104 { 105 init(); 106 n++; 107 for(i=1;i<n;i++) 108 { 109 scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z); 110 add(0,i,p[i].z*X); 111 } 112 for(i=1;i<n;i++) 113 { 114 scanf("%d",&k); 115 while(k--) 116 { 117 scanf("%d",&u); 118 if(u==i) 119 continue; 120 cost=dis(p[u],p[i])*Y; 121 if(p[u].z>p[i].z) 122 cost+=Z; 123 add(i,u,cost); 124 } 125 } 126 printf("%d\n",directedMST(0)); 127 } 128 return 0; 129 }