模板题:poj3164
定义:一个有向图,存在从某个点开始的到达所有的的一个最小生成树,则它就是最小树形图。
朱-刘算法的大概过程如下:
1、找到除了root以为其他点的权值最小的入边。用In[i]记录
2、如果出现除了root以外存在其他孤立的点,则不存在最小树形图。
3、找到图中所有的环,并对环进行缩点,重新编号。
4、更新其他点到环上的点的距离
假设有重新编号之前的节点u, v;编号之后为U, V
则dis[U][V] = dis[u][v] - In[V];
5、重复3,4知道没有环为止。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
using namespace std;
const int maxn = 105;
const int inf = 1e9 + 7;
struct Q
{
int u, v;
double c;
}edge[maxn * maxn];
struct P
{
double x, y;
P(double a, double b)
{
x = a, y = b;
}
P(){}
}node[maxn];
double dis(P A, P B)
{
return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
int n, m;
double in[maxn];
int pre[maxn];
int vis[maxn], id[maxn];
double MST(int s, int n, int m)
{
double res = 0;
while(true)
{/*****找所有点最小的入边*****/
for(int i = 1; i <= n; i++) in[i] = inf;
for(int i = 0; i < m; i++)
{
int u = edge[i].u, v = edge[i].v;
double c = edge[i].c;
if(c < in[v] && u != v)
{
pre[v] = u;
in[v] = c;
}
}
in[s] = 0;
for(int i = 1; i <= n; i++)
{
if(in[i] == inf) return -1; //原图不连通
}
/**********判断有没有环******/
memset(vis, -1, sizeof(vis));
memset(id, -1, sizeof(id));
int cnt = 1;
for(int i = 1; i <= n; i++)
{
res += in[i];
int v = i;
while(vis[v] != i && v != s && id[v] == -1)
{
vis[v] = i;
v = pre[v];
}
if(v != s && id[v] == -1)
{
for(int u = pre[v]; u != v; u = pre[u]) id[u] = cnt;
id[v] = cnt++;
}
}
if(cnt == 1)
{
break;
}
for(int i = 1; i <= n; i++)
{
if(id[i] == -1)
{
id[i] = cnt++;
}
}
/***********建立新图*****************/
for(int i = 0; i < m; i++)
{
int u = edge[i].u;
int v = edge[i].v;
edge[i].u = id[u];
edge[i].v = id[v];
if(id[u] != id[v]) edge[i].c -= in[v];
}
n = cnt - 1;
s = id[s];
}
return res;
}
int main()
{
while(~scanf("%d %d", &n, &m))
{
for(int i = 1; i <= n; i++)
{
scanf("%lf %lf", &node[i].x, &node[i].y);
}
for(int i = 0; i < m; i++)
{
scanf("%d %d", &edge[i].u, &edge[i].v);
edge[i].c = dis(node[edge[i].u], node[edge[i].v]);
if(edge[i].u == edge[i].v) edge[i].c = inf;
}
double ans = MST(1, n, m);
if(ans == -1) puts("poor snoopy");
else printf("%.2f\n", ans);
}
return 0;
}