#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<string.h>
using namespace std;
#define MAXN 110
#define INF 1000000000
#define clr(a,b); memset(a,b,sizeof(a));
struct Node
{
double x;
double y;
}node[MAXN];
int n,m;
int tmp;
bool visited[MAXN],circle[MAXN];
int pre[MAXN];
double map[MAXN][MAXN];
inline double dist(int i,int j)
{
return sqrt((node[i].x-node[j].x)*(node[i].x-node[j].x)+(node[i].y-node[j].y)*(node[i].y-node[j].y));
}
inline double min(double a,double b)
{
if(a<b)
return a;
return b;
}
void dfs(int u) /*深搜判断是否能够到达每个结点*/
{
if(visited[u])
return;
visited[u]=true;
for(int i=1;i<=n;i++)
{
if(!visited[i]&&map[u][i]!=INF)
{
dfs(i);
}
}
}
bool connect()
{
dfs(1);
for(int i=1;i<=n;i++)
{
if(!visited[i])
return false;
}
return true;
}
double zhu_liu()
{
double ans=0;int i,j,k;
clr(circle,0);//如果某点被删除了,那么circle[i]=1
while(1)
{
//求出除根节点以为每个结点入边的最小值
for(i=2;i<=n;i++)
{
if(circle[i]) continue;
map[i][i]=INF; //把图中所有的自环都清除,这一点很重要
pre[i]=i; //初始化自己的前一个结点是自己
for(j=1;j<=n;j++)
{
if(circle[j])
continue;
if(map[j][i]<map[pre[i]][i])
{
pre[i]=j;
}
}
}
//遍历找环
for(i=2;i<=n;i++)
{
if(circle[i])
continue;
j=i;
clr(visited,false);
while(!visited[j]&&j!=1)
{
visited[j]=true;
j=pre[j];
}
if(j==1)
continue;
i=j;
//把环的权值都加到ans里
ans+=map[pre[i]][i];
for(j=pre[i];j!=i;j=pre[j])
{
ans+=map[pre[j]][j];
circle[j]=1; //只用i代表这个环,其他的点都删掉,缩点
}
for(j=1;j<=n;j++)
{
if(circle[j]) continue;
if(map[j][i]!=INF)
map[j][i]-=map[pre[i]][i];
}
for(j=pre[i];j!=i;j=pre[j])
{
for(k=1;k<=n;k++)
{
if(circle[k]) continue;
if(map[j][k]!=INF)
map[i][k]=min(map[i][k],map[j][k]);
if(map[k][j]!=INF)
map[k][i]=min(map[k][i],map[k][j] - map[pre[j]][j]);
}
}
break;
}
if(i>n)
{
for(j=2;j<=n;j++)
{
if(circle[j])
continue;
ans+=map[pre[j]][j];
}
break;
}
}
return ans;
}
int main()
{
int i,j,u,v;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%lf%lf",&node[i].x,&node[i].y);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
map[i][j]=INF;
}
while(m--)
{
scanf("%d%d",&u,&v);
map[u][v]=dist(u,v);
}
clr(visited,false);
if(!connect())
printf("poor snoopy\n");
else
printf("%.2f\n",zhu_liu());
}
return 0;
}
朱刘算法——最小树形图
最新推荐文章于 2022-06-05 20:30:09 发布