LCA问题,用了离线的tarjan算法。输入输出参考了博客http://www.cnblogs.com/rainydays/archive/2011/06/20/2085503.html
tarjan算法是用了dfs+并查集的方式做的。这里输入输出有个不错的地方,就是用scanf("%[^0-9]", st);跳过非数字。
里面用数组g来表示多维的树,还用并查集的id数组的-1来表示是否访问。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define MAXN 909 /* g for the edges hasroot for whether the node is under root, it helps to identify the root id for disjoint-set lca for LCA of two nodes sum for the count for ancestors in result */ int n, root; bool g[MAXN][MAXN], hasroot[MAXN]; int id[MAXN], lca[MAXN][MAXN]; int sum[MAXN]; void input() { int a, b, m; char str[100]; memset(g, 0, sizeof(g)); memset(hasroot, 0, sizeof(hasroot)); for (int i = 0; i < n; i++) { scanf("%d", &a); a--; scanf("%[^0-9]", str); scanf("%d", &m); scanf("%[^0-9]", str); for (int i = 0; i < m; i++) { scanf("%d", &b); b--; hasroot[b] =true; g[a][b] = g[b][a] =true; } } for (int i = 0; i < n; i++) if (!hasroot[i]) { root = i; break; } } // for disjoint-set int find(int i) { if (id[i] == i) return i; return id[i] = find(id[i]);; } void merge(int i, int j) { id[find(i)] = find(j); } // do the tarjan algo and update lca table void tarjan(int rt) { id[rt] = rt; // id[k] != -1 means visited for (int i = 0; i < n; i++) if (g[rt][i] && id[i] == -1) { tarjan(i); merge(i, rt); // the order matters, because of the implementaion of merge } for (int i = 0; i < n; i++) if (id[i] != -1) lca[rt][i] = lca[i][rt] = find(i); } void solve() { int m; char str[100]; scanf("%d", &m); for (int i =0; i < m; i++) { int a, b; scanf("%[^0-9]", str); scanf("%d", &a); scanf("%[^0-9]", str); scanf("%d", &b); a--; b--; sum[lca[a][b]]++; } for (int i =0; i < n; i++) if (sum[i]) printf("%d:%d ", i + 1, sum[i]); } int main() { //freopen("d:\\t.txt", "r", stdin); while (scanf("%d", &n) != EOF) { char str[100]; input(); memset(id, -1, sizeof(id)); memset(sum, 0, sizeof(sum)); tarjan(root); solve(); scanf("%[^0-9]", str); } return 0; }