HDU-4009 Transfer water
阿新 • • 發佈:2018-11-02
把每個房子看作點,水渠看作邊,按照題目規則給點之間建邊
另外新建一個點作為水源點,和每個房子之間連邊,權值為height*x
從水源點求最小樹形圖就是答案,因為每個點都與源點連邊,所以這題一定有解
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int N=1000+10; const int M=1e6+10; const int INF=0x7f7f7f7f; struct Edge { int u,v,w; }edge[M]; int pre[N],vis[N],id[N],in[N]; int zhuliu(int root,int n,int m) { int sum=0; int u,v; while(true) { for(int i=0;i<n;i++) in[i]=INF; for(int i=0;i<m;i++) { Edge e=edge[i]; if(e.u!=e.v&&in[e.v]>e.w) { in[e.v]=e.w; pre[e.v]=e.u; } } for(int i=0;i<n;i++) if(i!=root&&in[i]==INF) return -1; int tn=0; memset(id,-1,sizeof(id)); memset(vis,-1,sizeof(vis)); in[root]=0; for(int i=0;i<n;i++) { sum+=in[i]; v=i; while(vis[v]!=i&&id[i]==-1&&v!=root) { vis[v]=i; v=pre[v]; } if(id[v]==-1&&v!=root) { for(u=pre[v];u!=v;u=pre[u]) id[u]=tn; id[v]=tn++; } } if(tn==0) break; for(int i=0;i<n;i++) if(id[i]==-1) id[i]=tn++; for(int i=0;i<m;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].w-=in[v]; } root=id[root]; n=tn; } return sum; } int a[N],b[N],c[N]; int main() { int n,x,y,z,k,v; while(~scanf("%d%d%d%d",&n,&x,&y,&z)&&(n||x||y||z)) { int cnt=0; for(int i=1;i<=n;i++) { scanf("%d%d%d",&a[i],&b[i],&c[i]); edge[cnt].u=0; edge[cnt].v=i; edge[cnt++].w=x*c[i]; } for(int i=1;i<=n;i++) { scanf("%d",&k); while(k--) { scanf("%d",&v); edge[cnt].u=i; edge[cnt].v=v; int w=y*(abs(a[i]-a[v])+abs(b[i]-b[v])+abs(c[i]-c[v])); if(c[i]<c[v]) w+=z; edge[cnt++].w=w; } } int ans=zhuliu(0,n+1,cnt); printf("%d\n",ans); } return 0; }