【HDU 4547 CD操作】LCA问题 Tarjan算法
題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4547
題意:模擬DOS下的cd命令,給出n個節點的目錄樹以及m次查詢,每個查詢包含一個當前目錄cur和一個目標目錄tar,返回從cur切換到tar所要使用的cd命令次數:
注意這里的cd命令是簡化版,只能進行如下兩種操作:
1.?cd ? .. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//返回父目錄
2.?cd ? cur\一系列目錄\tar ? ? ? ? ? ? ? ? //由當前目錄跳轉到目標目錄,注意中間的“一系列目錄”不能包含父目錄..,也就是說,自底向上必須一步步走,而自頂向下可以一步到位。
思路:用Tarjan算法求LCA,處理查詢時要分類討論:
1.?if tar == lca,則res(cur, tar) = depth(cur) - depth(lca); (包含tar == cur的情況)
2.?else if cur == lca, 則res(cur, tar) = 1;
3.?其他,則res(cur, tar) = depth(cur) - depth(lca) + 1;
這道題還有些細節問題需要處理好:
1. 每個查詢要記錄好目標目錄是誰。因為tarjan算法是批處理的,即每完成對一個棵子樹的遍歷,處理其樹根所涉及到的查詢。為使查詢處理不遺漏,我們把查詢也以鄰接表的形式存成雙向邊,然而每次處理需要知道本次查詢原始的“單向邊”,這樣才能根據上面的分類計算結果。所以我另設了一個數組ans_tar[i]記錄第 i 個查詢所給定的tar。
2. 同HDU2586這道題,多個查詢,注意記錄查詢序列號。這道題我用鄰接表項query_id[r][i]記錄節點r的第i個查詢所持有的查詢序列號,用鄰接表項query_tar[r][i]記錄節點r的第i個查詢的目標節點。
3. 給出的目錄是字符串,要用一個map<string, int>存儲名稱到節點號的映射關系。
這里又了解到了map一個用法,即對[]的重載:對于map<string, int> m,如果調用一次m[s],而s在m中不存在時,會自動插入s并將它的value置為0。這個設計對于這道題很合適,可以維護全局計數變量seq_num,如果返回0的話,分發下一個序號給它即可。
1 #include <cstdio> 2 #include <iostream> 3 #include <vector> 4 #include <map> 5 #include <string> 6 #include <cstring> 7 using namespace std; 8 const int MAX_N = 100005; 9 const int MAX_M = 100005; 10 11 int vis[MAX_N]; 12 int ans[MAX_N]; 13 int ans_tar[MAX_N];//每組查詢的目標目錄 14 int indeg[MAX_N]; 15 int depth[MAX_N]; 16 map<string, int> name; 17 vector<int> G[MAX_N];//鄰接表,邊不帶權 18 vector<int> query_tar[MAX_N]; 19 vector<int> query_id[MAX_N]; 20 int par[MAX_N]; 21 22 int T; 23 int n, m; 24 int seq_num;//目錄名的序列號,從1開始 25 26 void init(){ 27 seq_num = 1; 28 memset(vis, 0, sizeof(vis)); 29 memset(ans, 0, sizeof(ans)); 30 memset(ans_tar, 0, sizeof(ans_tar)); 31 memset(indeg, 0, sizeof(indeg)); 32 memset(depth, 0, sizeof(depth)); 33 name.clear(); 34 for(int i=0; i<MAX_N; i++){ 35 G[i].clear(); 36 query_tar[i].clear(); 37 query_id[i].clear(); 38 par[i] = i; 39 } 40 } 41 int find(int x){ 42 return par[x]==x ? x : par[x] = find(par[x]); 43 } 44 void unite(int x, int y){ 45 x = find(x); 46 y = find(y); 47 if(x==y) return ; 48 par[y] = x; 49 } 50 51 void dfs(int r, int l){ 52 //cout << "dfs " << r << endl; 53 vis[r] = 1; 54 depth[r] = l; 55 for(int i=0; i<G[r].size(); i++){ 56 //cout << G[r][i] << endl; 57 if(vis[G[r][i]]) continue; 58 dfs(G[r][i], l+1); 59 unite(r, G[r][i]); 60 } 61 for(int i=0; i<query_tar[r].size(); i++){ 62 if(!vis[query_tar[r][i]]) continue; 63 int cur, tar; 64 int ans_id = query_id[r][i];//這一查詢所持的序列號 65 int real_tar = ans_tar[ans_id];//這一個查詢真正指定的target 66 if(r == real_tar){//當前r是目標 67 cur = query_tar[r][i]; 68 tar = real_tar; 69 }else{//已訪問過的那個點是目標 70 cur = r; 71 tar = real_tar; 72 } 73 //cout << "query " << cur << tar << endl; 74 int ca = find(query_tar[r][i]); 75 if(tar == ca) ans[ans_id] = depth[cur] - depth[ca]; 76 else if(cur == ca) ans[ans_id] = 1; 77 else ans[ans_id] = depth[cur] - depth[ca] + 1; 78 } 79 } 80 81 void lca(int r){ 82 //cout << "root " << r << endl; 83 dfs(r, 0); 84 } 85 86 int main() 87 { 88 freopen("4547.txt", "r", stdin); 89 scanf("%d", &T); 90 while(T--){ 91 init(); 92 scanf("%d%d", &n, &m); 93 for(int i=0; i<n-1; i++){ 94 string c, p; 95 cin>>c; 96 int u = name[c];//不存在會自動插入并置value為0 97 if(u==0){ 98 u = name[c] = seq_num++; 99 } 100 101 cin>>p; 102 int v = name[p]; 103 if(v==0){ 104 v = name[p] = seq_num++; 105 } 106 G[u].push_back(v); 107 G[v].push_back(u); 108 indeg[u]++;//入度為0的是根目錄 109 } 110 // for(map<string, int>::iterator iter = name.begin(); 111 // iter != name.end(); iter++){ 112 // cout << iter->first << iter->second << endl; 113 // } 114 for(int i=0; i<m; i++){ 115 string cur, tar; 116 cin >> cur >> tar; 117 int u = name[cur]; 118 int v = name[tar]; 119 query_tar[u].push_back(v); 120 query_tar[v].push_back(u); 121 query_id[u].push_back(i);//tar和id是同步記錄的 122 query_id[v].push_back(i); 123 ans_tar[i] = v;//為辨誰是目標目錄 124 } 125 for(map<string, int>::iterator iter = name.begin(); 126 iter != name.end(); iter++){ 127 int id = iter->second; 128 if(indeg[id] == 0){ 129 lca(id); 130 break; 131 } 132 } 133 for(int i=0; i<m; i++){ 134 printf("%d\n", ans[i]); 135 } 136 } 137 return 0; 138 } 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的【HDU 4547 CD操作】LCA问题 Tarjan算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JQuery 常用积累(六)ZTree
- 下一篇: Azure手把手系列 1:微软中国公有云