参考了芳哥的博文 http://blog.csdn.net/wsniyufang/article/details/6747392
说一下自己的理解。
最开始的图,把所有的最小入边都累加到ret里。至于为什么,因为这样才能保证所得的ret有可能是最小树形图的解,当然,是在这些最小入边集合不行成环得情况下。
如果有了环,ret肯定不是最终答案,因为环中间有的边需要删掉,而且环之间也要连接起来。现在我们无法得知删除环中的哪些边才行。这就需要建立新图了。
举个例子:某个图的部分图中, 1->2权值为3, 2->1权值为4, 3->1权值为9, 4->2权值为7。 那么可以看到,结点1和结点2是形成了一个环的。我们仅从其大小不知道删除哪条边比较好,这时看到3->1权值为9, 如果走这条边,那么接下来只能删除掉2->1这条边,同理走4->2的话就要删除掉1->2这条边。 那么就不妨建立新图, 将1和2缩成一点,3->1的权值就变成了9-4=5, 4->2的权值变成了7-3=4。 这样的话,就相当于变相删除了不需要走的边了。形成新图后,又变成了最小树形图的求解,就这样循环下去,直到图中的最小边集没有环为止。
/*
ID: CUGB-wwj
PROG:
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define INF 2000000000
#define MAXN 105
#define MAXM 1005
#define L(x) x<<1
#define R(x) x<<1|1
#define eps 1e-4
using namespace std;
typedef double type;
struct Point
{
double x, y;
}p[MAXN];
struct node
{
int u, v;
type w;
}edge[MAXN * MAXN];
int pre[MAXN], id[MAXN], vis[MAXN], n, m;
type in[MAXN];
double dis(Point a, Point b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
type Directed_MST(int root, int V, int E)
{
type ret = 0;
while(true)
{
//1.找最小入边
for(int i = 0; i < V; i++) in[i] = INF;
for(int i = 0; i < E; i++)
{
int u = edge[i].u;
int v = edge[i].v;
if(edge[i].w < in[v] && u != v) {pre[v] = u; in[v] = edge[i].w;}
}
for(int i = 0; i < V; i++)
{
if(i == root) continue;
if(in[i] == INF) return -1;//除了跟以外有点没有入边,则根无法到达它
}
//2.找环
int cnt = 0;
memset(id, -1, sizeof(id));
memset(vis, -1, sizeof(vis));
in[root] = 0;
for(int i = 0; i < V; i++) //标记每个环
{
ret += in[i];
int v = i;
while(vis[v] != i && id[v] == -1 && v != root) //每个点寻找其前序点,要么最终寻找至根部,要么找到一个环
{
vis[v] = i;
v = pre[v];
}
if(v != root && id[v] == -1)//缩点
{
for(int u = pre[v]; u != v; u = pre[u]) id[u] = cnt;
id[v] = cnt++;
}
}
if(cnt == 0) break; //无环 则break
for(int i = 0; i < V; i++)
if(id[i] == -1) id[i] = cnt++;
//3.建立新图
for(int i = 0; i < E; 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].w -= in[v];
}
V = cnt;
root = id[root];
}
return ret;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
for(int i = 0; i < n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
for(int i = 0; i < m; i++)
{
scanf("%d%d", &edge[i].u, &edge[i].v);
edge[i].u--;
edge[i].v--;
if(edge[i].u != edge[i].v) edge[i].w = dis(p[edge[i].u], p[edge[i].v]);
else edge[i].w = INF; //去除自环
}
type ans = Directed_MST(0, n, m);
if(ans == -1) printf("poor snoopy\n");
else printf("%.2f\n", ans);
}
return 0;
}