题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
给一个图,找两个点最近公共祖先。
这几天数据取证课上得蛋疼,根本没有时间看什么算法。今晚翘课做大物实验,回来虽然没下课但是也不想去了。于是窝在实验室做一两道题爽一下也是不错的。
膜拜一下tarjan,据说以tarjan命名的算法有三个,好强啊,什么时候我也能像他一样呢(恐怕一辈子都不可能了吧(笑))
插入边的时候统计出入度,以便后来选择谁来做根节点。同时为了查询方便,我用map来存边。这道题解决完输入问题后,开始标记每一个节点在我刚刚标记的图上的层次遍历的深度和它的相应父节点,之后就可以查询最近公共祖先了,注意查询的时候先加边权再更新点。
代码:
1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <climits> 6 #include <complex> 7 #include <fstream> 8 #include <cassert> 9 #include <cstdio> 10 #include <bitset> 11 #include <vector> 12 #include <deque> 13 #include <queue> 14 #include <stack> 15 #include <ctime> 16 #include <set> 17 #include <map> 18 #include <cmath> 19 20 using namespace std; 21 22 typedef struct Edge { 23 int u, v; 24 int next; 25 }Edge; 26 27 typedef pair<int, int> pii; 28 const int maxn = 40010; 29 int n, m; 30 int ecnt; 31 int head[maxn]; 32 int depth[maxn], parent[maxn]; 33 int in[maxn], out[maxn]; 34 int root; 35 map<pii, int> el; 36 Edge e[maxn]; 37 38 void init() { 39 ecnt = 0; 40 el.clear(); 41 memset(head, -1, sizeof(head)); 42 memset(e, 0, sizeof(e)); 43 } 44 45 void adde(int u, int v, int w) { 46 e[ecnt].u = u; 47 e[ecnt].v = v; 48 in[v]++; 49 out[u]++; 50 e[ecnt].next = head[u]; 51 head[u] = ecnt++; 52 el[pii(u, v)] = w; 53 } 54 55 void dfs(int u, int p, int d) { 56 parent[u] = p; 57 depth[u] = d; 58 for(int i = head[u]; ~i; i = e[i].next) { 59 if(p != e[i].v) { 60 dfs(e[i].v, u, d+1); 61 } 62 } 63 } 64 65 int lca(int u, int v) { 66 int ans = 0; 67 while(depth[u] > depth[v]) { 68 ans += el[pii(parent[u], u)]; 69 u = parent[u]; 70 } 71 while(depth[v] > depth[u]) { 72 ans += el[pii(parent[v], v)]; 73 v = parent[v]; 74 } 75 while(u != v) { 76 ans += el[pii(parent[u], u)]; 77 ans += el[pii(parent[v], v)]; 78 u = parent[u]; 79 v = parent[v]; 80 } 81 return ans; 82 } 83 84 int main() { 85 // freopen("in", "r", stdin); 86 int T; 87 int u, v, w; 88 scanf("%d", &T); 89 while(T--) { 90 init(); 91 scanf("%d %d", &n, &m); 92 for(int i = 0; i < n-1; i++) { 93 scanf("%d %d %d", &u, &v, &w); 94 adde(u, v, w); 95 } 96 for(int i = 1; i <= n; i++) { 97 if(in[i] == 0) { 98 root = i; 99 break; 100 } 101 } 102 dfs(root, -1, 0); 103 while(m--) { 104 scanf("%d %d", &u, &v); 105 printf("%d ", lca(u, v)); 106 } 107 } 108 return 0; 109 }
也可以把map换成一个hash,数据太水可以这么搞。
#include <algorithm> #include <iostream> #include <iomanip> #include <cstring> #include <climits> #include <complex> #include <fstream> #include <cassert> #include <cstdio> #include <bitset> #include <vector> #include <deque> #include <queue> #include <stack> #include <ctime> #include <set> #include <map> #include <cmath> using namespace std; typedef struct Edge { int u, v; int next; }Edge; typedef pair<int, int> pii; const int maxn = 40010; const int mod = 1111111; int n, m; int ecnt; int head[maxn]; int depth[maxn], parent[maxn]; int in[maxn], out[maxn]; int root; int has[mod]; Edge e[maxn]; #define con(u, v) ((parent[u]*1005)%mod+(u*217)%mod)%mod void init() { ecnt = 0; memset(has, 0, sizeof(has)); memset(head, -1, sizeof(head)); memset(e, 0, sizeof(e)); } void adde(int u, int v, int w) { e[ecnt].u = u; e[ecnt].v = v; in[v]++; out[u]++; e[ecnt].next = head[u]; head[u] = ecnt++; has[((u*1005)%mod+(v*217)%mod)%mod] = w; } void dfs(int u, int p, int d) { parent[u] = p; depth[u] = d; for(int i = head[u]; ~i; i = e[i].next) { if(p != e[i].v) { dfs(e[i].v, u, d+1); } } } int lca(int u, int v) { int ans = 0; while(depth[u] > depth[v]) { ans += has[con(u, u)]; u = parent[u]; } while(depth[v] > depth[u]) { ans += has[con(v, v)]; v = parent[v]; } while(u != v) { ans += has[con(u, u)]; ans += has[con(v, v)]; u = parent[u]; v = parent[v]; } return ans; } int main() { // freopen("in", "r", stdin); int T; int u, v, w; scanf("%d", &T); while(T--) { init(); scanf("%d %d", &n, &m); for(int i = 0; i < n-1; i++) { scanf("%d %d %d", &u, &v, &w); adde(u, v, w); } for(int i = 1; i <= n; i++) { if(in[i] == 0) { root = i; break; } } dfs(root, -1, 0); while(m--) { scanf("%d %d", &u, &v); printf("%d ", lca(u, v)); } } return 0; }