hdu4009最小树形图
多建一个根,连到每一个点,然后花费是建水井的钱
然后跑一边最小树形图即可,这题必定有解,因为可以从根开始到每一点,可以不用判无解的情况
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<map> #include<set> #include<ctime> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<iomanip> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define pi acos(-1) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define MIN(a,b) a<b ? a:b using namespace std; const double g=10.0,eps=1e-9; const int N=1000+10,maxn=500000+10,inf=0x3f3f3f3f; struct edge{ int u,v,w; }e[maxn]; struct pe{ int x,y,z; }p[N]; int pre[N],in[N],vis[N]; int ans,Hash[N]; int dis(int a,int b) { return abs(p[a].x-p[b].x)+abs(p[a].y-p[b].y)+abs(p[a].z-p[b].z); } bool dirmst(int root,int nv,int ne) { ans=0; while(1){ memset(in,inf,sizeof in); for(int i=0;i<ne;i++) { int u=e[i].u,v=e[i].v; if(e[i].w<in[v]&&u!=v) { in[v]=e[i].w; pre[v]=u; } } in[root]=0; for(int i=0;i<nv;i++) if(in[i]==inf) return 0; int cntnum=0; memset(vis,-1,sizeof vis); memset(Hash,-1,sizeof Hash); for(int i=0;i<nv;i++) { ans+=in[i]; int v=i; while(vis[v]!=i&&v!=root&Hash[v]==-1)vis[v]=i,v=pre[v]; if(v!=root&&Hash[v]==-1) { for(int u=pre[v];u!=v;u=pre[u]) Hash[u]=cntnum; Hash[v]=cntnum++; } } if(cntnum==0)return 1; for(int i=0;i<nv;i++) if(Hash[i]==-1) Hash[i]=cntnum++; for(int i=0;i<ne;i++) { int v=e[i].v; e[i].v=Hash[e[i].v]; e[i].u=Hash[e[i].u]; if(e[i].v!=e[i].u)e[i].w-=in[v]; } nv=cntnum; root=Hash[root]; } return 1; } int main() { ios::sync_with_stdio(false); cin.tie(0); int n,x,y,z; while(cin>>n>>x>>y>>z){ if(n==0&&x==0&&y==0&&z==0)break; for(int i=1;i<=n;i++)cin>>p[i].x>>p[i].y>>p[i].z; int cnt=0; for(int i=1;i<=n;i++) { int k,s; cin>>k; while(k--){ cin>>s; e[cnt].u=i; e[cnt].v=s; e[cnt].w=dis(i,s)*y; if(p[s].z>p[i].z)e[cnt].w+=z; cnt++; } } for(int i=1;i<=n;i++) { e[cnt].u=0; e[cnt].v=i; e[cnt].w=x*p[i].z; cnt++; } dirmst(0,n+1,cnt)) cout<<ans<<endl; } return 0; }