#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int maxn=100+5;
const int maxm=10000+5;
double inf;
double x[maxn],y[maxn];
int s[maxm],e[maxm];
double dis[maxm],in[maxn];
int pre[maxn],color[maxn],vis[maxn];
int n,m;
void MDST(int root)
{
double ans=0;
while(true)
{
memset(in,127,sizeof(in));
memset(pre,-1,sizeof(pre));
//选最短边
for(int i=1;i<=m;i++){
if(dis[i]<in[e[i]]&&s[i]!=e[i]){
pre[e[i]]=s[i];in[e[i]]=dis[i];
}
}
//如果有第二个点入度为0,那么最小树形图不存在
for(int i=1;i<=n;i++) if(pre[i]==-1&&i!=root) {printf("poor snoopy\n");return ;}
int cnt=0;in[root]=0;
memset(color,-1,sizeof(color));
memset(vis,-1,sizeof(vis));
for(int i=1;i<=n;i++){
int u,v=i;ans+=in[i];
while(v!=root&&vis[v]==-1) {vis[v]=i;v=pre[v];}//找环
if(v!=root&&vis[v]==i)
for(color[v]=++cnt,u=pre[v];u!=v;u=pre[u]) color[u]=cnt;//给环染色
}
if(!cnt) break;//无环
for(int i=1;i<=n;i++) if(color[i]==-1) color[i]=++cnt;//给剩余的点染色
//处理图,断开环上的in[i]边,其他进入边全部-in[i]
for(int i=1;i<=m;i++){
int u=s[i],v=e[i];
s[i]=color[u];e[i]=color[v];
if(color[u]!=color[v]) dis[i]-=in[v];
}
n=cnt;root=color[root];//更新图
}
printf("%.2f\n",ans);
}
int main()
{
memset(in,127,sizeof(in));inf=in[1];
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]);
for(int i=1;i<=m;i++) {
scanf("%d%d",&s[i],&e[i]);
dis[i]=(s[i]==e[i]?inf:hypot(x[s[i]]-x[e[i]],y[s[i]]-y[e[i]]));
}
MDST(1);
}
return 0;
}
POJ 3164 Command Network(最小树形图+朱刘算法)
最新推荐文章于 2021-04-07 17:04:49 发布