思路:就是裸的最小树形图~
#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=;
LL ans=;
while()
{
for(i=;i<=n;i++) in[i]=inf;
for(i=;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=;i<=n;i++)
{
if(i==root) continue;
if(in[i]==inf) return -;
}
memset(vi,-,sizeof(vi));
memset(id,-,sizeof(id));
cnt=;
in[root]=;
for(i=;i<=n;i++)//枚举每个可能是环上的点
{
ans+=in[i];
v=i;
while(vi[v]!=i&&id[v]==-&&v!=root)
{
vi[v]=i;v=pre[v];
}
if(v!=root&&id[v]==-)//如果退出上个循环的条件不是v==root,就是vi[i]==i,即找到了环
{
id[v]=++cnt;
for(u=pre[v];u!=v;u=pre[u])//对环进行统一标号
id[u]=cnt;
}
}
if(cnt==) break;//无环 ,退出
for(i=;i<=n;i++) if(id[i]==-) id[i]=++cnt;
for(i=;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=;
for(i=;i<=n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
for(i=;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(a!=b)
add(a,b,Dis(p[a],p[b]));
}
double ans=directed_MST(,n,num);
if(ans==-)
printf("poor snoopy\n");
else
printf("%.2lf\n",ans);
}
return ;
}