/* http://hi.baidu.com/bin183/blog/item/45c37950ece4475f1138c273.html 最小树形图(有向图的最小生成树)思想:对于有根的图,首先求出每个点费用最小的前驱边,如果这些前驱边构成了回路, 那么缩点,同时以这个大点中的某个点为终点的边的权值减去这个点在圈中的前驱边的权值。不断重复这过程,直至没有回路。 对于没有根的图,另加一个根,权值为所有权值的和,这样的话,与根相连的边只会选择一条,所以求的值再减去即可。 题意:有一些村庄,现要求使所有村庄都有水的最少费用。每个村庄可以通过挖井,从别的村庄拉水管的方式使村庄有水。 分析:因为每个村庄都可以挖井,所以没有不可能的情况。然后新加一个结点,表示挖井的费用,而后再根据输入构图。求最小树形图即可 因为数据较大,要用邻接表的实现。时间复杂度为O(V*E) */ #include<stdio.h> #include<string.h> #include<cmath> #include<iostream> const int maxn=1100; const int maxm=1100000; const int maxint=0x3fffffff; struct edge { int u,v,w; edge(){} edge(int u1,int v1,int w1):u(u1),v(v1),w(w1){} }e[maxm]; int root,n,edgeNum,vis[maxn],pre[maxn],belong[maxn],in[maxn]; int a[maxn],b[maxn],c[maxn]; int Abs(int a) { return a>0? a:-a; } int Dis(int i,int j) { return Abs(a[i]-a[j])+Abs(b[i]-b[j])+Abs(c[i]-c[j]); } int solve() { int i,j,k,num,sum=0; n++;//开始是0至n,n+1个点 while(1)//不断缩点,直至不含圈 { for(i=0;i<n;i++) in[i]=maxint; for(i=0;i<edgeNum;i++)//找每个点的前驱边 { if(in[e[i].v]>e[i].w&&e[i].u!=e[i].v) { pre[e[i].v]=e[i].u; in[e[i].v]=e[i].w; } } memset(vis,-1,sizeof(vis)); memset(belong,-1,sizeof(belong)); in[root]=0; for(num=0,i=0;i<n;i++) { sum+=in[i];//加上每个点的前驱边 j=i; while(vis[j]!=i&&belong[j]==-1&&j!=root)//判断是否有圈 { vis[j]=i; j=pre[j]; } if(vis[j]==i)//j一定在圈上,而i不一定 { for(k=pre[j];k!=j;k=pre[k])//第num个圈,缩点 belong[k]=num; belong[j]=num++; } } if(!num) return sum;//不含圈,则结束 for(i=0;i<n;i++) if(belong[i]==-1)//不属于某个圈的是独立的点 belong[i]=num++; for(i=0;i<edgeNum;i++) { int j=e[i].v; e[i].u=belong[e[i].u]; e[i].v=belong[e[i].v]; e[i].w-=in[j];//注意是减去缩点前的前驱边,而不是in[e[i].v] } n=num; root=belong[root]; } return sum; } int main() { int x,y,z,i,j,k,ii,d; while(scanf("%d%d%d%d",&n,&x,&y,&z)!=EOF) { if(!n&&!x&&!y&&!z) break; for(edgeNum=0,i=1;i<=n;i++) { scanf("%d%d%d",&a[i],&b[i],&c[i]); e[edgeNum++]=edge(0,i,c[i]*x); } for(i=1;i<=n;i++) { scanf("%d",&k); while(k--) { scanf("%d",&ii); if(i==ii) continue; d=Dis(i,ii); if(c[i]>=c[ii])//i向ii提供水 e[edgeNum++]=edge(i,ii,d*y); else e[edgeNum++]=edge(i,ii,d*y+z); } } root=0; printf("%d\n",solve()); } return 0; }