#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44935891");
}
算法构造过程以及傻叉代码+弱版注释见以前博客
http://blog.csdn.net/vmurder/article/details/38819711
每次将所有点(根除外)最小弧长度累加,重建图时与x相连的边权值全部减去此最小弧长度,这样就保证了最后一个点的流程中加得的所有最小弧长度等于最后一次加的边的原长度。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define inf 0x3f3f3f3f
#define N 200
#define M 50000
using namespace std;
struct Fiona
{
double x,y;
}s[N];
struct Syndra
{
int u,v;
double w;
}e[M];
int pre[N],f[N],vis[N];
double l[N];
double dist(Fiona A,Fiona B)
{
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
double Directed_MST(int root,int n,int m)
{
int i,j,k;
int u,v,cnt;
double ans=0;
while(1)
{
for(i=1;i<=n;i++)f[i]=vis[i]=0,l[i]=inf;
for(i=1;i<=m;i++)
{
u=e[i].u;v=e[i].v;
if(l[v]>e[i].w)pre[v]=u,l[v]=e[i].w;
}
for(i=1;i<=n;i++)if(l[i]==inf&&i!=root)return -1;
l[root]=cnt=0;
for(i=1;i<=n;i++)
{
ans+=l[i];
if(vis[i])continue;
for(v=i;!vis[v]&&v!=root;vis[v]=i,v=pre[v]);
if(v!=root&&vis[v]==i)
{
f[v]=++cnt;
for(u=pre[v];u!=v;u=pre[u])f[u]=cnt;
}
}
if(!cnt)break;
for(i=1;i<=n;i++)if(!f[i])f[i]=++cnt;
n=cnt,cnt=0,root=f[root];
for(i=1;i<=m;i++)
{
u=e[i].u,v=e[i].v;
if(f[u]!=f[v])
{
e[++cnt].u=f[u];
e[cnt].v=f[v];
e[cnt].w=e[i].w-l[v];
}
}
m=cnt;
}
return ans;
}
int main()
{
freopen("test.in","r",stdin);
int i,n,m;
double ans;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)scanf("%lf%lf",&s[i].x,&s[i].y);
for(i=1;i<=m;i++)
{
scanf("%d%d",&e[i].u,&e[i].v);
if(e[i].u!=e[i].v)e[i].w=dist(s[e[i].u],s[e[i].v]);
else i--,m--;
}
ans=Directed_MST(1,n,m);
if(ans==-1)printf("poor snoopy\n");
else printf("%.2f\n",ans);
}
return 0;
}
【POJ3164】Command Network 最小树形图模板题 重修版
原文地址:http://blog.csdn.net/vmurder/article/details/44935891