# DSA-HW4-NonProgrammingPart ## B07902060 資工一 趙雋同 ### Problem 1. k-th Largest Element #### 1. ```clike= typedef struct RBtree{ int color; int value; int descendants; struct RBtree *left , *right , *parent; }rb; int sz(rb *root){ if(root == NULL) return 0; root->descendants = sz(root->left) + sz(root->right) + 1; return root->descendants; } ``` 利用遞迴遍歷整棵RB tree,如果root是NIL的話,就return 0代表該節點沒有子孫,若不是NIL的話,即為其左右子孫的descendants的數量加上自己(+1)。由於每個節點只會走到一次,所以time-complexity是O(n). #### 2. 由於需要變動的sz(x)只有插入時被訪問到的節點,且紅黑數的高度為$O(logn)$,那麼調整sz(x)的time-complexity為$O(logn)$,而因為紅黑樹本身的插入也為$O(logn)$,所以整體需要$O(logn)$的時間。 #### 3. 跟第二小題差不多的概念,我們只要更新訪問過的節點就好,從root開始,直到找到要刪除的節點,我令所有訪問過的節點的sz(x)皆減一,之後在找predecesor或是successor時,也令所有訪問過得節點的sz(x)減一,再讓predecesor(or succesor)移到要刪除的節點後並將它的sz value等於刪除的節點的sz value-1,而因為紅黑樹的高度為$O(logn)$,所以刪除以及調整sz(x)的time-complexity為$O(logn)$ #### 4. 假設要執行left-rotate(X),且X的left-child為A而right-child為Y,Y又有其left-child B和right-child C 。於是我們可以知道在rotate前: $sz(X)=sz(A)+sz(Y)+1=sz(A)+sz(B)+sz(C)+2$ $sz(Y)=sz(B)+sz(C)+1$ 而因為node A,B,C他們在rotate之後children不變,所以$sz(A),sz(B),sz(C)$維持不變,而X的ancestor的children總數不變,所以只要考慮$sz(X)$以及$sz(Y)$的變化,而我們知道rotate之後: $sz(X)=sz(A)+sz(B)+1$ $sz(Y)=sz(X)+sz(C)+1=sz(A)+sz(B)+sz(C)+2$ ```clike= rotate-sz(x) a = sz(x.left) c = sz(y.left) tmp1 = sz(x) tmp2 = sz(y) sz(x) = tmp2-c+a sz(y) = tmp1 ``` 可以看出rotate-sz(x)的time-complexity是 $O(1)$ #### 5 ```clike= int find_kth_largest(rb *root ,int k){ if(k == sz(root->right)+1 ) return root->value; else if (k <= sz(root->right) ) return find_kth_largest(root->right , k); else return find_kth_largest(root->left , k-sz(root->right)-1 ); } ``` 分成三種情況: ***(a)*** : 依照RB tree的建構規則,root的左子孫皆小於他;右子孫皆大於他,所以如果k等於sz(root->right)+1的話,root就是該子樹k'th largest element ***(b)*** : 假如k小於等於sz(root->right)的話,就代表我們要尋找的在右子樹中,由於右小孩皆大於root,所以我們找的還是右子樹裡的k'th largest element,以遞迴帶入。 ***\(c\)*** : 如果k大於sz(root->right)+1的話,代表k'th largest element 在左子樹中,由於root跟root的右小孩全大於root的左小孩,所以我們改為尋找左子樹中(k-sz(root->right)-1)'th largest element,同樣以遞迴帶入。 ----------- ### Problem 2. Strongly Connected Component #### 1 ![](https://i.imgur.com/FchpQF2.png) #### 2 strongly connected component在reverve後依舊是strongly connected,那麼能夠reduce的點集合先reverese再reduce跟先reduce再reverse會是一樣的結果。 #### 3 ```clike= #include<stdio.h> #include<stdlib.h> #define MAXN 100 #define Slen 1000 typedef struct Edge{ int index; struct Edge *next; }edge; typedef struct Vertex{ edge *next; int color; int pi; int d; int f; }vertex; int N; vertex V[MAXN]; vertex reversingV[MAXN]; int ts; int Stack[Slen] = {0}; int ptr = -1; int gr = 1; int SSC[MAXN]; void Push(int data){ Stack[++ptr] = data; } int Pop(){ return Stack[ptr--]; } void DFS_visit(int u){ ++ts; V[u].d = ts; V[u].color = 1; edge *next = V[u].next; while(next != NULL){ if(V[next->index].color == 0){ V[next->index].pi = u; DFS_visit(next->index); } next = next->next; } V[u].color = 2; ++ts; V[u].f = ts; Push(u); } void DFS(){ for(int i=0;i<N;i++){ V[i].color = 0; V[i].pi = -1; } ts = 0; for(int i=0;i<N;i++) if(V[i].color == 0) DFS_visit(i); } void build_edge(vertex cur[] , int x ,int y){ edge *new = (edge*)malloc(sizeof(edge)); new->index = y; new->next = cur[x].next; cur[x].next = new; } void reverse_DFS_visit(int u){ ++ts; reversingV[u].d = ts; reversingV[u].color = 1; edge *next = reversingV[u].next; while(next != NULL){ if(reversingV[next->index].color == 0){ SSC[next->index] = gr; reversingV[next->index].pi = u; reverse_DFS_visit(next->index); } next = next->next; } reversingV[u].color = 2; ++ts; reversingV[u].f = ts; } void find_SSC(){ int v; ts = 0; for(int i=0;i<N;i++){ reversingV[i].color = 0; reversingV[i].pi = -1; } while(ptr != -1){ v = Pop(); //printf("%d\n",v); if(reversingV[v].color == 0){ SSC[v] = gr; reverse_DFS_visit(v); gr++; } } } int main(){ int edge_N; int x,y; scanf("%d%d",&N,&edge_N); for(int i=0;i<edge_N;i++){ scanf("%d%d",&x,&y); build_edge(V,x,y); build_edge(reversingV,y,x); } DFS(); //printf("%d\n",ptr); find_SSC(); for(int i=0;i<N;i++) printf("%d'th vertex is in group %d\n",i,SSC[i]); return 0; } ``` 在V & reversingV 的build_edge中的time-complexity是 $O(E)$ DFS的方面time-complexity $O(V+E)$ find_SSC的方面只是作reversingV 的DFS,所以也是 $O(V+E)$ print SSC的部份是 $O(V)$ 所以整個code的time-complexity就是 $O(V+E)$