题目链接: poj 3164
有向图的最小树形图:此算法由朱永津和刘振宏在1965年发表。
膜拜--
写下自己理解的思路--- 一天一道题----痛并快乐着--
解题步骤:
1》先从根节点DFS一下,看是否有解--
2》寻找除根节点外的所有点的最小入边--
3》从所有点向上寻找--看中间路径是否存在环--(如果不存在环,说明已经找到最小树形图--将各边加入ans中--算法结束)
4》如果存在环的话就先将环上各边之和加入ans--然后找各点的其他入边并更新(因为已将最小入边加上--其他入边以后如果还用时就应该用它与最小入边的差值)
---然后-收缩环为环中一点--除收缩点外,其他点与外界的状态全部转移到收缩点--其他点标记一下(隐藏)--然后返回步骤2.
图文可在百度文库下载:最小树形图
代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
#define M 999999999
double x[120],y[120];
double map[120][120];
bool fafe[120];
double dist(int xx,int yy)
{
double lp=sqrt((x[xx]-x[yy])*(x[xx]-x[yy])+(y[xx]-y[yy])*(y[xx]-y[yy]));
return lp;
}
int fer[120];
double zhuliu()
{
int pre[120],i;
bool visit[120];
double ans=0;
for (int i=1;i<=n;i++)
{
fafe[i]=false;
map[i][i]=M;
}
pre[1]=1;
while (true)
{
for (i=2;i<=n;i++)
{
if (fafe[i])continue;
pre[i]=i;
for (int j=1;j<=n;j++)
{
if (!fafe[j]&&map[j][i]<map[pre[i]][i])
pre[i]=j;
}
}
for (i=2;i<=n;i++)
{
if (fafe[i])continue;
memset(visit,false,sizeof(visit));
visit[1]=true;
int j=i;
do
{
visit[j]=true;
j=pre[j];
}while(!visit[j]);
if (j==1) continue;//从根节点出发--到i之间无环。
i=j;/*这里是i=j,,,写成j=i就超时--- 如果有环时j不是回到i了吗??
原来是从i想上找---循环可能没有i---如:3——4---5----4:pre[3]=4--pre[4]=5---pre[5]=4;
这样的话--如果下面的循环还是从i开始--但是判断结果是就j!=i--永远会不到3的位置--就会 Time Limit Exceeded*/
do
{
ans+=map[pre[j]][j];
j=pre[j];
}while (j!=i);
j=i;
do//改变权值
{
for (int k=1;k<=n;k++)
{
if (fafe[k]) continue;
if (map[k][j]<M&&k!=pre[j])
map[k][j]-=map[pre[j]][j];
}
j=pre[j];
}while (j!=i);
for (j=1;j<=n;j++)//将与环上的点相连的路全部连在i上
{
if (j==i) continue;
for (int k=pre[i];k!=i;k=pre[k])
{
if (map[k][j]<map[i][j]) map[i][j]=map[k][j];
if (map[j][k]<map[j][i]) map[j][i]=map[j][k];
}
}
for (j=pre[i];j!=i;j=pre[j])//除i点,其他点隐藏
fafe[j]=true;
break;// 此环已压缩--当做一点--重新找每点的最短入边--
}
if (i==n+1)//从2到n都无环---
{
for (int j=2;j<=n;j++)
if (!fafe[j])
ans+=map[pre[j]][j];
break;
}
}
return ans;
}
void DFS(int xx)
{
fafe[xx]=false;
for (int i=1;i<=n;i++)
if (fafe[i]&&map[xx][i]!=M)
DFS(i);
return ;
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
map[i][j]=M;
for (int i=1;i<=n;i++)
scanf("%lf%lf",&x[i],&y[i]);
int a,b;
for (int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
if (a==b) continue;
map[a][b]=dist(a,b);
}
bool falg=true;
memset(fafe,true,sizeof(fafe));
DFS(1);
for (int i=1;i<=n;i++)
if (fafe[i])
{
falg=false;
break;
}
if (falg)
printf("%.2lf\n",zhuliu());
else
printf("poor snoopy\n");
}
return 0;
}