http://poj.org/problem?id=3164
继续测测最小树形图板子
#include<cstdio>
#include<cmath>
using namespace std;
const int maxl=2e4+10;
const int inf=1e9+10;
int n,m;double ans=0;
int x[maxl],y[maxl];
double ine[maxl];int pre[maxl],vis[maxl],id[maxl];
struct ed
{
int u,v;double w;
}e[maxl];
inline double dist(int u,int v)
{
return sqrt(1.0*(x[u]-x[v])*(x[u]-x[v])+1.0*(y[u]-y[v])*(y[u]-y[v]));
}
inline void prework()
{
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=m;i++)
{
int u,v;scanf("%d%d",&u,&v);
e[i]=ed{u,v,dist(u,v)};
}
}
inline double zhuliu()
{
double ans=0;int rt=1;
while(1)
{
for(int i=1;i<=n;i++) ine[i]=inf;
for(int i=1;i<=m;i++)
{
int u=e[i].u,v=e[i].v;
if(u!=v && e[i].w<ine[v])
ine[v]=e[i].w,pre[v]=u;
}
for(int i=1;i<=n;i++)
if(i!=rt && ine[i]==inf)
return -1;
int cnt=0;
for(int i=1;i<=n;i++)
vis[i]=id[i]=0;
for(int i=1;i<=n;i++)
{
if(i==rt) continue;
ans+=ine[i];
int v=i;
while(vis[v]!=i && !id[v] && v!=rt)// find circle
{
vis[v]=i;
v=pre[v];
}
if(!id[v] && v!=rt)//circle to point
{
id[v]=++cnt;
for(int u=pre[v];u!=v;u=pre[u])
id[u]=cnt;
}
}
if(cnt==0) break;//no circle
for(int i=1;i<=n;i++)
if(!id[i])
id[i]=++cnt;
for(int i=1;i<=m;i++)
{
int u=e[i].u,v=e[i].v;
e[i].u=id[u],e[i].v=id[v];
if(id[u]!=id[v])//ine[v] add to ans, more edge = del original edge
e[i].w-=ine[v];
}
rt=id[rt];n=cnt;
}
return ans;
}
inline void mainwork()
{
ans=zhuliu();
}
inline void print()
{
if(ans<0)
puts("poor snoopy");
else
printf("%.2f\n",ans);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
prework();
mainwork();
print();
}
return 0;
}