分析:建一个远点,往每个点连建井的价值(单向边),其它输水线按照题意建单向边
然后以源点为根的权值最小的有向树就是答案,套最小树形图模板
#include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <stack> #include <queue> #include <cmath> #include <vector> using namespace std; typedef long long LL; const int N=1e3+5; const int INF=0x7f7f7f7f; struct Edge{ int u,v; LL w; }edge[N*N]; struct Node{ LL x,y,z; }p[N]; LL in[N]; int id[N],vis[N],pre[N],n,m; LL zhuliu(int rt,int n,int m){ int ret=0; while(1){ for(int i=1;i<=n;++i)in[i]=INF; for(int i=1;i<=m;++i){ if(edge[i].u!=edge[i].v&&edge[i].w<in[edge[i].v]){ pre[edge[i].v]=edge[i].u; in[edge[i].v]=edge[i].w; } } for(int i=1;i<=n;++i) if(i!=rt&&in[i]==INF)return -1; int cnt=0; memset(id,-1,sizeof(id)); memset(vis,-1,sizeof(vis)); in[rt]=0; for(int i=1;i<=n;++i){ ret+=in[i]; int v=i; while(vis[v]!=i&&id[v]==-1&&v!=rt){ vis[v]=i; v=pre[v]; } if(v!=rt&&id[v]==-1){ ++cnt; for(int u=pre[v];u!=v;u=pre[u]) id[u]=cnt; id[v]=cnt; } } if(cnt==0)break; for(int i=1;i<=n;++i) if(id[i]==-1)id[i]=++cnt; for(int i=1;i<=m;++i){ int u=edge[i].u,v=edge[i].v; edge[i].u=id[u]; edge[i].v=id[v]; if(id[u]!=id[v])edge[i].w-=in[v]; } n=cnt; rt=id[rt]; } return ret; } LL dis(int i,int j){ return abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y)+abs(p[i].z-p[j].z); } int main() { LL X,Y,Z; while(~scanf("%d%I64d%I64d%I64d",&n,&X,&Y,&Z)){ if(!n)break; for(int i=1;i<=n;++i) scanf("%I64d%I64d%I64d",&p[i].x,&p[i].y,&p[i].z); int cnt=0; for(int i=1;i<=n;++i){ int k; scanf("%d",&k); for(int j=1;j<=k;++j){ int u=i,v; scanf("%d",&v); if(u==v)continue; ++cnt; edge[cnt].u=u,edge[cnt].v=v; edge[cnt].w=dis(u,v)*Y; if(p[u].z<p[v].z)edge[cnt].w+=Z; } } for(int i=1;i<=n;++i){ ++cnt; edge[cnt].u=n+1; edge[cnt].v=i; edge[cnt].w=X*p[i].z; } LL ans=zhuliu(n+1,n+1,cnt); printf("%I64d ",ans); } return 0; }