最小树形图,朱刘算法,步骤见下: http://hi.baidu.com/goldengoatish/blog/item/a8e693d8aad5122611df9b2e.html/cmtid/0b36bd097aac9f980a7b8295 代码: #include<iostream> #include<cmath> using namespace std; const int MAX=105; const double inf=99999999.9; int x[MAX],y[MAX],vis[MAX],pre[MAX],inCircle[MAX]; double g[MAX][MAX],minCost[MAX],ans; int n,m,root; double getDis(int i,int j) { double xx=x[i]-x[j],yy=y[i]-y[j]; return sqrt(xx*xx+yy*yy); } void dfs(int u) { vis[u]=1; for(int v=1;v<=n;v++) { if(!vis[v]&&g[u][v]!=inf) dfs(v); } } bool exist() { for(int i=1;i<=n;i++) if(!vis[i]) return false; return true; } int findCircle() { int i,j; root=1; pre[root]=root; for(i=1;i<=n;i++) { if(!inCircle[i]&&i!=root) { pre[i]=i; g[i][i]=inf;//消去自环 for(j=1;j<=n;j++) { if(!inCircle[j]&&g[j][i]<g[pre[i]][i]) { pre[i]=j; } } } } for(i= 1;i<= n;++i)//判断是否存在有向环 { if(inCircle[i]) continue; memset(vis,false,sizeof(vis)); int j= i; while(!vis[j]) { vis[j]= true; j= pre[j]; } if(j==root) continue; return j; } return -1; } void update(int t)//缩点 { int i,j; ans+=g[pre[t]][t]; for(i=pre[t];i!=t;i=pre[i]) { inCircle[i]=1;//点i被缩掉,不存在 ans+=g[pre[i]][i]; } for(i=1;i<=n;i++) if(!inCircle[i]&&g[i][t]!=inf) g[i][t]-=g[pre[t]][t]; for(j=pre[t];j!=t;j=pre[j]) { for(i=1;i<=n;i++) { if(!inCircle[i]&&g[i][j]!=inf) { g[i][t]=min(g[i][t],g[i][j]-g[pre[j]][j]); //g[t][j]=min(g[i][j],g[t][j]); } g[t][i]=min(g[j][i],g[t][i]); } } } void solve() { int i,t; memset(inCircle,0,sizeof(inCircle)); while((t=findCircle())!=-1) { update(t); } for(i=1;i<=n;i++) { if(i!=root&&!inCircle[i]) ans+=g[pre[i]][i]; } printf("%.2lf/n",ans); } int main() { int i,j; while(scanf("%d%d",&n,&m)!=EOF) { memset(vis,0,sizeof(vis)); ans=0; root=1; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) g[i][j]=inf; } for(i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]); while(m--) { scanf("%d%d",&i,&j); g[i][j]=getDis(i,j); } dfs(1); if(!exist()) { printf("poor snoopy/n"); continue; } else solve(); } return 0; }