最小树形图模版题,学习了一下最小树形图。
三步走,找最小入弧,找有向环,缩环为点。
#include <string.h> #include <stdio.h> #include <stdlib.h> #define INF 0x3f3f3f3f #define MAXN 1001 struct edge{ int u,v,w; }e[MAXN*MAXN]; int n,x,y,z,es,k,tt; int pnt[MAXN][3]; int dist(int p1,int p2){ int ret=0; for(int i=0;i<3;i++)ret+=abs(pnt[p1][i]-pnt[p2][i]); return ret; } void addedge(int u,int v,int w){ e[es].u=u,e[es].v=v,e[es].w=w,es++; } /*点和边都是从0开始的,root包含在点集中*/ int in[MAXN],pre[MAXN],id[MAXN],vis[MAXN]; int dir_mst(int root,int vs,int es){ int ret=0; for(;;){ int size=vs*4; memset(in,0x3f,size); memset(id,-1,size); memset(vis,-1,size); //step1:找最小入弧 for(int i=0;i<es;i++){ int u=e[i].u,v=e[i].v,w=e[i].w; if(w>=in[v]||u==v)continue; pre[v]=u,in[v]=w; } in[root]=0,pre[root]=root; //如果有孤立点说明无解 for(int i=0;i<vs;i++){ ret+=in[i]; if(in[i]==INF)return -1; } //step2:找有向环 int idx=0; for(int i=0;i<vs;i++)if(vis[i]==-1){ int u=i; while(vis[u]==-1)vis[u]=i,u=pre[u]; if(vis[u]!=i||u==root)continue; for(int t=pre[u];t!=u;t=pre[t])id[t]=idx; id[u]=idx++; } //没有环,已经完成 if(idx==0)break; for(int i=0;i<vs;i++)if(id[i]==-1)id[i]=idx++; //step3:将环缩为点 for(int i=0;i<es;i++){ e[i].w-=in[e[i].v]; e[i].u=id[e[i].u]; e[i].v=id[e[i].v]; } vs=idx; root=id[root]; } return ret; } int main(){ freopen("test.in","r",stdin); while(scanf("%d%d%d%d",&n,&x,&y,&z),n||x||y||z){ for(int i=1;i<=n;i++) scanf("%d%d%d",&pnt[i][0],&pnt[i][1],&pnt[i][2]); es=0; for(int i=1;i<=n;i++) addedge(0,i,pnt[i][2]*x); for(int i=1;i<=n;i++){ scanf("%d",&k); while(k--){ scanf("%d",&tt); if(pnt[i][2]>=pnt[tt][2])addedge(i,tt,dist(i,tt)*y); else addedge(i,tt,dist(i,tt)*y+z); } } int res=dir_mst(0,n+1,es); if(res==-1)printf("poor XiaoA\n"); else printf("%d\n",res); } }