大意:有向树的的最小权值和。
思路:(有向树不是无向所以不能用prim做)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<limits.h>
using namespace std;
const int MAXN = 110;
const int MAXM = 10010;
struct node
{
int from;
int to;
double w;
};
node e[MAXM];
struct node1
{
double x;
double y;
};
node1 Point[MAXN];
double Dist(node1 a, node1 b)
{
double x=a.x-b.x;
double y=a.y-b.y;
return sqrt(x*x+y*y);
}
int pre[MAXN],vis[MAXN],flag[MAXN];
double In[MAXN],sum;
double ZhuLiu(int root,int N,int M)
{
sum=0;
while(true)
{
for(int i=0;i<N;++i)
In[i]=INT_MAX;
for(int i=0;i<M;++i)
{
int u=e[i].from;
int v=e[i].to;
if(e[i].w<In[v]&&u!= v)
{
pre[v]=u;//v为终点,pre[v]存放起点
In[v]=e[i].w;//权值最小的边
}
}
for(int i=0;i<N;++i)//如果存在除root以外的孤立点,则不存在最小树形图
{
if(i==root)
continue;
if(In[i]==INT_MAX)
return -1;
}
int CntNode=0;
memset(flag,-1,sizeof(flag));
memset(vis,-1,sizeof(vis));
In[root]=0;
for(int i=0;i<N;++i) //找环,标记每个环
{
sum+=In[i];
int v=i;
while(vis[v]!=i&&flag[v]==-1&&v!=root)//每个点寻找其前序点,要么最终寻找至根部,要么找到一个环
{
vis[v]=i;
v=pre[v];
}
if(v!=root&&flag[v]==-1) //新图重新编号
{
for(int u=pre[v];u!=v;u=pre[u])
flag[u]=CntNode;
flag[v]=CntNode++;
}
}
if(CntNode==0) //无环,跳出
break;
for(int i=0;i<N;++i)
{
if(flag[i]==-1)
flag[i]=CntNode++;
}
for(int i=0;i<M;++i) //建立新图,更新其他点到环的距离
{
int v=e[i].to;
e[i].from=flag[e[i].from];
e[i].to=flag[e[i].to];
if(e[i].from!=e[i].to)
e[i].w-=In[v];
}
N=CntNode;
root=flag[root];
}
return sum;
}
int main()
{
int x,y,N,M;
while(~scanf("%d%d",&N,&M))
{
int id=0;
for(int i=0;i< N;++i)
scanf("%lf%lf",&Point[i].x,&Point[i].y);
for(int i=0;i<M;++i)
{
scanf("%d%d",&x,&y);
if(x==y)
continue;
x--;
y--;
e[id].from=x;
e[id].to=y;
e[id++].w=Dist(Point[x],Point[y]);
}
double ans=ZhuLiu(0,N,id);
if(ans==-1)
printf("poor snoopy\n");
else
printf("%.2f\n",ans);
}
return 0;
}