poj 3164 最小树形图
思路:就是裸的最小树形图~
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define Maxn 110 #define LL double #define inf 1e9 using namespace std; int pre[Maxn],id[Maxn],vi[Maxn],num; LL in[Maxn]; struct Edge{ int u,v; LL val; }edge[Maxn*Maxn]; struct Point{ double x,y; }p[Maxn]; double Dis(Point a,Point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void add(int u,int v,LL val) { edge[num].u=u,edge[num].v=v,edge[num++].val=val; } LL directed_MST(int root,int n,int e) { int i,j,u,v,cnt=0; LL ans=0; while(1) { for(i=1;i<=n;i++) in[i]=inf; for(i=0;i<e;i++)//找最小入边 { u=edge[i].u; v=edge[i].v; if(in[v]>edge[i].val&&v!=u) { in[v]=edge[i].val; pre[v]=u; } } for(i=1;i<=n;i++) { if(i==root) continue; if(in[i]==inf) return -1; } memset(vi,-1,sizeof(vi)); memset(id,-1,sizeof(id)); cnt=0; in[root]=0; for(i=1;i<=n;i++)//枚举每个可能是环上的点 { ans+=in[i]; v=i; while(vi[v]!=i&&id[v]==-1&&v!=root) { vi[v]=i;v=pre[v]; } if(v!=root&&id[v]==-1)//如果退出上个循环的条件不是v==root,就是vi[i]==i,即找到了环 { id[v]=++cnt; for(u=pre[v];u!=v;u=pre[u])//对环进行统一标号 id[u]=cnt; } } if(cnt==0) break;//无环 ,退出 for(i=1;i<=n;i++) if(id[i]==-1) id[i]=++cnt; for(i=0;i<e;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].val-=in[v]; } n=cnt; root=id[root]; } return ans; } int main() { int i,j,n,m,a,b; while(scanf("%d%d",&n,&m)!=EOF) { num=0; for(i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); if(a!=b) add(a,b,Dis(p[a],p[b])); } double ans=directed_MST(1,n,num); if(ans==-1) printf("poor snoopy\n"); else printf("%.2lf\n",ans); } return 0; }