POJ 1470 -- Closest Common Ancestors
阿新 • • 發佈:2018-02-01
bre else common 多次提交 flag 變量 spa pro int 題目鏈接:http://poj.org/problem?id=1470
Closest Common Ancestors
nr_of_vertices
vertex:(nr_of_successors) successor1 successor2 ... successorn
...
where vertices are represented as integers from 1 to n ( n <= 900 ). The tree description is followed by a list of pairs of vertices, in the form:
nr_of_pairs
(u v) (x y) ...
The input file contents several data sets (at least one).
Note that white-spaces (tabs, spaces and line breaks) can be used freely in the input.
For example, for the following tree:
Time Limit: 2000MS | Memory Limit: 10000K | |
Total Submissions: 21483 | Accepted: 6812 |
Description
Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two nodes u and v is the node w that is an ancestor of both u and v and has the greatest depth in the tree. A node can be its own ancestor (for example in Figure 1 the ancestors of node 2 are 2 and 5)Input
nr_of_vertices
vertex:(nr_of_successors) successor1 successor2 ... successorn
...
where vertices are represented as integers from 1 to n ( n <= 900 ). The tree description is followed by a list of pairs of vertices, in the form:
nr_of_pairs
(u v) (x y) ...
The input file contents several data sets (at least one).
Note that white-spaces (tabs, spaces and line breaks) can be used freely in the input.
Output
For example, for the following tree:
Sample Input
5 5:(3) 1 4 2 1:(0) 4:(0) 2:(1) 3 3:(0) 6 (1 5) (1 4) (4 2) (2 3) (1 3) (4 3)
Sample Output
2:1 5:5
Hint
Huge input, scanf is recommended. 題意:給出頂點數,各頂點的子節點數目和編號,詢問次數,每次詢問的頂點對,要求輸出詢問中出現的最近公共祖先和與其對應的詢問次數; 題解&總結: 1. LCA裸題,下面給出Tarjan離線解法的代碼,Tarjan算法網上已有許多不錯的講解,在此不再贅述,把dfs和並查集理解好Tarjan算法也就挺好理解了; 2. 輸入有多組數據,註意把數組和變量初始化; 3. 輸入的第一個數是節點數,不一定是根節點,根節點的確定應該通過排除子節點,剩下的一個就是根節點; 4. 代碼中以前向星來儲存邊,當然用vector來實現鄰接表也可以,但顯然前向星比vector更快; 5. 題目中只給出了最大節點數,但並沒有給出最大詢問次數,經多次提交實驗,最大詢問次數應該在250000左右,註意開足夠大的數組; 6. 通過此題可以發現,數組開小了不止可能會RE,還可能會訪問到垃圾數據使dfs無窮遞歸而MLE,也可能出現死循環而TLE; 7. 題目提示推薦用scanf輸入,本著倔強的精神試了cin輸入也還是可以1900+MS過了。1 #include <iostream> 2 #include <stdio.h> 3 #include <cstring> 4 #define N 1010 5 #define MAXQ 250010 6 using namespace std; 7 struct node{ 8 int next, to, lca; 9 } edge[2*N], qedge[2*MAXQ]; // 儲存邊,依次儲存詢問 10 int num_edge, num_qedge, head[N], qhead[N]; 11 int fa[N]; 12 bool vis[N], flag[N]; 13 void add_edge(int from, int to) { // 前向星添加邊 14 edge[++num_edge].next = head[from]; 15 edge[num_edge].to = to; 16 head[from] = num_edge; 17 } 18 void add_qedge(int from, int to) { 19 qedge[++num_qedge].next = qhead[from]; 20 qedge[num_qedge].to = to; 21 qhead[from] = num_qedge; 22 } 23 int Find(int x) { 24 if (fa[x] != x) fa[x] = Find(fa[x]); 25 return fa[x]; 26 } 27 void dfs(int x) { 28 fa[x] = x; 29 vis[x] = true; 30 for (int k = head[x]; k; k = edge[k].next) { 31 if (!vis[edge[k].to]) { 32 dfs(edge[k].to); 33 fa[edge[k].to] = x; 34 } 35 } 36 for (int k = qhead[x]; k; k = qedge[k].next) { 37 if (vis[qedge[k].to]) { 38 qedge[k].lca = Find(qedge[k].to); 39 if (k & 1) qedge[k+1].lca = qedge[k].lca; 40 else qedge[k-1].lca = qedge[k].lca; 41 } 42 } 43 } 44 void init() { // 初始化 45 memset(vis, false, sizeof(vis)); 46 memset(flag, false, sizeof(flag)); 47 memset(head, 0, sizeof(head)); 48 memset(qhead, 0, sizeof(qhead)); 49 num_edge = num_qedge = 0; 50 } 51 52 int main() { 53 int n, x, y, k; 54 char ch; 55 ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 56 while (cin >> n) { 57 init(); 58 for (int i = 0; i < n; i++) { 59 cin >> x >> ch >> ch >> k >> ch;//scanf("%d%*c%*c%d%*c", &x, &k); 60 while (k--) { 61 cin >> y;//scanf(" %d", &y); 62 flag[y] = true; 63 add_edge(x, y); add_edge(y, x); 64 } 65 66 } 67 cin >> k;//scanf("%d", &k); 68 for (int i = 0; i < k; i++) { 69 cin >> ch >> x >> y >> ch;//scanf(" %*c%d %d%*c", &x, &y); 70 add_qedge(x, y); add_qedge(y, x); 71 } 72 for (int i = 1; i <= n; i++) if (!flag[i]) dfs(i); // 確定根節點 73 int cnt[N]; memset(cnt, 0, sizeof(cnt)); 74 for (int i = 1; i <= k; i++) cnt[qedge[i*2].lca]++; 75 for (int i = 1; i <= n; i++) if (cnt[i]) cout << i << ‘:‘ << cnt[i] << endl;//printf("%d:%d\n", i, cnt[i]); 76 } 77 78 return 0; 79 }View Code
POJ 1470 -- Closest Common Ancestors