(最小树形图)POJ 3164 - Command Network
题意:
给定一个有向图,求以某个给定顶点为根的有向生成树(也就是说沿着这N-1条有向边可以从根走到任一点),使权和最小。
分析:
这题直接朱刘算法,虽然看起来很偏门,但是还是要学一下。算法过程很多博客都有了,这里就不赘述了。
不过貌似CSU1828是朱刘算法+AC自动机,可以刷一刷。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 #include <cmath> 7 8 using namespace std; 9 10 const int inf = 0x3f3f3f3f; 11 const int maxn = 110; 12 13 14 int n, m; 15 double x[maxn], y[maxn]; 16 17 double dis(double x1, double y1, double x2, double y2) { 18 return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)); 19 } 20 21 struct Edge { 22 int u, v; 23 double c; 24 }; 25 26 Edge edge[10010]; 27 28 double in[maxn]; 29 int pre[maxn]; 30 int id[maxn]; 31 int vis[maxn]; 32 33 double MTV(int root) { 34 double ans = 0; 35 while(1) { 36 for(int i = 0; i < n; i++) in[i] = inf; 37 for(int i = 0; i < m; i++) { 38 int u = edge[i].u; 39 int v = edge[i].v; 40 if(edge[i].c < in[v] && u != v) { 41 in[v] = edge[i].c; 42 pre[v] = u; 43 } 44 } 45 46 for(int i = 0; i < n; i++) { 47 if(i == root) continue; 48 if(in[i] == inf) return -1; 49 } 50 51 int cnt = 0; 52 memset(id, -1, sizeof(id)); 53 memset(vis, -1, sizeof(vis)); 54 in[root] = 0; 55 for(int i = 0; i < n; i++) { 56 ans += in[i]; 57 int v = i; 58 while(vis[v] != i && id[v] == -1 && v != root) { 59 vis[v] = i; 60 v = pre[v]; 61 } 62 if(v != root && id[v] == -1) { 63 for(int u = pre[v]; u != v; u = pre[u]) { 64 id[u] = cnt; 65 } 66 id[v] = cnt++; 67 } 68 } 69 if(cnt == 0) break; 70 71 for(int i = 0; i < n; i++) { 72 if(id[i] == -1) id[i] = cnt++; 73 } 74 75 for(int i = 0; i < m; i++) { 76 int v = edge[i].v; 77 edge[i].v = id[edge[i].v]; 78 edge[i].u = id[edge[i].u]; 79 if(edge[i].u != edge[i].v) { 80 edge[i].c -= in[v]; 81 } 82 } 83 n = cnt; 84 root = id[root]; 85 } 86 return ans; 87 } 88 89 90 91 int main() { 92 while(~scanf("%d%d", &n, &m)) { 93 for(int i = 0; i < n; i++) { 94 scanf("%lf%lf", &x[i], &y[i]); 95 } 96 for(int i = 0; i < m; i++) { 97 int u, v; 98 scanf("%d%d", &u, &v); 99 u--, v--; 100 if(u == v)edge[i] = Edge{u, v, inf}; 101 else edge[i] = Edge{u, v, dis(x[u], y[u], x[v], y[v])}; 102 } 103 double ans = MTV(0); 104 if(ans < 0)puts("poor snoopy"); 105 else printf("%.2f\n", ans); 106 } 107 108 return 0; 109 110 }