参考了芳哥的博文 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; }