113 年 國立臺灣大學資料科學碩士學位學程《資料結構與演算法》
第 1 題5 分
Consider the following variation of the Selection Problem: Given a sequence of distinct integers and two positive integers and , where each number in falls between 1 and , the goal is to report the smallest numbers in in ascending order. This scenario assumes the conventional single-processor, random access machine (RAM) model, with a machine word size of at least bits. To tackle this problem, five algorithms have been proposed. Please select the correct description(s) below.
A. Algorithm A: The algorithm initializes an empty max-heap and sequentially inserts numbers from . During insertion, if the size of the max-heap exceeds , it removes the maximum element from the heap. Finally, the remaining numbers in the heap are sorted by heapsort and reported. If , Algorithm A runs in time in the worst case.
B. Algorithm B: The algorithm initially constructs a min-heap and proceeds to extract the minimum element times. If , Algorithm B runs in time in the worst case.
C. Algorithm C: The algorithm performs counting by performing a base- radix sort, followed by reporting the smallest values. If , Algorithm C runs in time in the worst case.
D. Algorithm D: The algorithm performs a counting sort by allocating an array of length , traversing through and incrementing for each . It finally reports the smallest values by scanning through the counter array. If , Algorithm D runs in time in the worst case.
E. Algorithm E: The algorithm first applies quickselect, i.e., Randomized-Select, to determine the -th smallest number in . Subsequently, it traverses for extracting numbers smaller than or equal to the -th smallest number. Finally, these numbers are sorted by quicksort and reported. The time complexity of Algorithm E is in expectation.
登入後即可作答並保存紀錄。
好的,同學你好!這題是國立臺灣大學資訊工程學研究所 113 年資料結構與演算法考題的第一題,主要在考驗你對「選擇問題 (Selection Problem)」及其變形問題的理解,以及各種排序與選擇演算法(如堆積排序、基數排序、計數排序、快速選擇等)的時間複雜度分析能力,特別是在不同輸入規模與資料特性(、、)下的表現。這類問題是資料結構與演算法的經典考題,務必掌握各種演算法的適用情境與複雜度。
完整解題過程
題目要求從給定的 個相異整數序列 中,找出最小的 個數字,並以遞增順序回報。序列中的每個數字介於 到 之間。我們將逐一分析每個演算法的描述與其時間複雜度。
A. Algorithm A: 使用最大堆積 (Max-Heap)
演算法描述:
此演算法初始化一個空的 Max-Heap。依序將 中的數字插入堆積。在插入過程中,如果堆積的大小超過 ,則移除堆積中的最大元素。最後,將堆積中剩餘的 個數字使用堆積排序 (Heapsort) 進行排序並回報。
時間複雜度分析:
- 初始化 Max-Heap: 。
- 插入 個數字並維護堆積大小: 對於序列 中的每個數字 :
- 將 插入 Max-Heap。此操作的時間複雜度為 ,其中 是堆積的當前大小。由於堆積大小最多為 ,因此每次插入為 。
- 如果堆積大小超過 ,則移除最大元素(即堆積的根)。此操作的時間複雜度為 。
- 總共有 個數字,因此此階段的總時間複雜度為 。
- 對堆積中剩餘的 個數字進行排序: 堆積中包含 個最小的數字。使用 Heapsort 對這 個數字進行排序,時間複雜度為 。
- 總時間複雜度: 。
判斷條件: 如果 ,演算法 A 在最壞情況下運行時間為 。
將 代入總時間複雜度 :
。
顯然, 不等於 。例如,當 接近 時,時間複雜度會是 級別,而非 。
結論: 選項 A 的描述是錯誤的。
B. Algorithm B: 使用最小堆積 (Min-Heap)
演算法描述:
此演算法首先從所有 個數字中建構一個 Min-Heap,然後從中提取最小元素 次。
時間複雜度分析:
- 建構 Min-Heap: 從 個數字建構一個 Min-Heap 的時間複雜度為 。
- 提取最小元素 次: 每次提取最小元素(即堆積的根)並重新堆積的時間複雜度為 。總共提取 次,因此此階段的總時間複雜度為 。
- 總時間複雜度: 。
判斷條件: 如果 ,演算法 B 在最壞情況下運行時間為 。
將 代入總時間複雜度 :
。
結論: 選項 B 的描述是正確的。
C. Algorithm C: 使用基數排序 (Radix Sort)
第 2 題5 分
A Maximum Binary Tree (abbreviated as MaxBT) is defined as a binary tree that adheres to the max-heap property without the necessity of following the complete binary tree property. In a MaxBT, each node consists of a value (.data) and two links (.left and .right) pointing to the left and right children, respectively. A link to nil indicates the absence of further children.
The provided pseudocode, although incomplete, implements a recursive function for merging two MaxBTs into a single MaxBT. This function takes the root nodes of the two MaxBTs (root1 and root2) as input and returns the root node of the merged MaxBT.
1: function MergeMaxBinaryTrees(root1, root2)
2: if root1 = nil then return (a) end if
3: if root2 = nil then return (b) end if
4: if root1.data > root2.data then
5: (c) ← MergeMaxBinaryTrees( (d) , (c) )
6: return (f)
7: else
8: (g) ← MergeMaxBinaryTrees( (h) , (i) )
9: return (j)
10: end if
11: end function
Assuming all the blanks in the above description have been appropriately filled to ensure its proper functioning, please select the correct description(s) below.
A. (b) and (f) are the same.
B. (c), (d), and (e) are all distinct.
登入後即可作答並保存紀錄。
本題考驗的核心觀念是遞迴式二元樹合併 (Recursive Binary Tree Merging),特別是針對最大二元樹 (Maximum Binary Tree, MaxBT) 的合併操作。MaxBT 遵循最大堆積性質 (max-heap property),即每個節點的值都大於或等於其子節點的值,但不要求是完全二元樹。解題關鍵在於理解遞迴合併的基底情況 (base cases) 和遞迴步驟 (recursive steps),以及如何透過遞迴呼叫來維護 MaxBT 的性質。
完整解題過程:
首先,我們需要根據 MaxBT 的性質和遞迴合併的邏輯,推導出空白處應填入的內容,以確保函數能「正常運作 (proper functioning)」。
一個 MaxBT 合併函數的標準邏輯如下:
- 基底情況 (Base Cases):
- 如果
root1為nil,則合併結果就是root2。 - 如果
root2為nil,則合併結果就是root1。
- 如果
- 遞迴步驟 (Recursive Step):
- 比較
root1.data和root2.data。為了簡化邏輯,我們通常會確保root1總是指向值較大的那個根節點。如果root1.data < root2.data,則交換root1和root2。 - 現在,
root1擁有較大的值,它將成為合併後 MaxBT 的根節點。 - 將值較小的樹 (
root2) 遞迴地合併到root1的其中一個子樹中(例如,右子樹root1.right)。 - 返回
root1作為合併後的根節點。
- 比較
根據上述邏輯,我們來填寫題目中的偽程式碼:
1: function MergeMaxBinaryTrees (root1, root2)
2: if root1 == nil then return (a)
3: end if
4: if root2 == nil then return (b)
5: end if
6: if root1.data > root2.data then
7: (c) = MergeMaxBinaryTrees(root1, (d))
8: return (e)
9: else // root2.data >= root1.data
10: (f) = MergeMaxBinaryTrees((g), root2)
11: return (h)
12: end if
13: end function
填寫空白處:
-
第 2 行:
if root1 == nil then return (a)- 如果
root1為空,則合併結果就是root2。 - 所以,
(a)應為root2。
- 如果
-
第 4 行:
if root2 == nil then return (b)- 如果
root2為空,則合併結果就是root1。 - 所以,
(b)應為root1。
- 如果
-
第 6-8 行 (if root1.data > root2.data):
- 此時
root1的值較大,它將成為合併後的根節點。 - 所以,
(e)應為root1。 - 值較小的樹 (
root2) 需要被合併到root1的子樹中。通常會選擇其中一個子節點(例如root1.right或root1.left)。我們假設選擇root1.right。 - 遞迴呼叫的目的是將
root2合併到root1.right中,並將結果賦值給root1.right。 - 因此,第 7 行的正確形式應為
root1.right = MergeMaxBinaryTrees(root1.right, root2)。 - 對應到
(c) = MergeMaxBinaryTrees(root1, (d)),這表示題目中的偽程式碼在MergeMaxBinaryTrees的第一個參數root1處有誤植。為了使函數「正常運作」,我們必須假設其意圖是root1.right。 - 所以,
(c)應為root1.right(代表root1.right這個變數被賦值)。 (d)應為root2(代表被合併的較小樹的根節點)。
- 此時
-
第 9-11 行 (else, 即 root2.data >= root1.data):
- 此時
root2的值較大,它將成為合併後的根節點。 - 所以,
(h)應為root2。 - 值較小的樹 (
root1) 需要被合併到root2的子樹中。同樣假設選擇root2.right。 - 遞迴呼叫的目的是將
root1合併到root2.right中,並將結果賦值給root2.right。 - 因此,第 10 行的正確形式應為
root2.right = MergeMaxBinaryTrees(root2.right, root1)。
- 此時
第 3 題5 分
A Dynamic Array (abbreviated as DArray) is a type of array that permits the insertion and deletion of elements at the end to dynamically adjust its size. DArray D maintains three crucial attributes, including the underlying array D.data, the logical data size D.size, and the actual array capacity D.capacity. The invariant D.size ≤ D.capacity holds at any given moment. The Insert(D, x) operation appends the element x to the end of D.data. In case D.size = D.capacity, it triggers a call to Resize(D) before appending x, where Resize(D) allocates a new and larger array, moves all the data to it, increases the value of D.capacity, sets up D.data, and finally frees the old array. Two implementations of Resize(D) are provided: ResizeA(D) increases D.capacity by a constant (e.g., 10) while ResizeB(D) doubles D.capacity each time.
To initialize DArray D, we set D.size to 0, D.capacity to 1, and allocate a size 1 array to D.data. Assuming that both allocating and freeing arrays of length n take O(n) time, and moving a single element takes O(1) time, please select the correct description(s) below.
A. DArray is not suitable for random access because its memory may be relocated.
B. DArray can only be allocated in the heap memory due to its dynamic memory nature.
C. If ResizeA(D) is considered, the amortized time complexity of Insert(D, x) is O(1).
D. If ResizeB(D) is considered, the amortized time complexity of Insert(D, x) is O(1).
E. In the Delete(D) operation, if D.size > 0, D.size is decreased by 1. If, at this stage, D.size < [D.capacity/2], we create a new array d' with a size of [D.capacity/2], transfer the data to d', set up d' as the new data array for D.data, and subsequently free the old array. Then, the amortized time complexity of mixed Insert and Delete operations can be O(1), where Resize(D) can be either ResizeA(D) or ResizeB(D).
登入後即可作答並保存紀錄。
本題主要考驗考生對動態陣列 (Dynamic Array) 的核心概念、記憶體管理方式,以及在不同擴容 (resize) 策略下,插入 (Insert) 和刪除 (Delete) 操作的攤還時間複雜度 (amortized time complexity) 的理解。特別是對於攤還分析 (amortized analysis) 的掌握,是解題的關鍵。
完整解題過程
A. DArray is not suitable for random access because its memory may be relocated.
- 說明: 陣列 (Array) 的一個基本特性是它支援隨機存取 (random access),即透過索引 (index) 在 時間內存取任何元素。這是因為陣列的元素在記憶體中是連續儲存的。
- 動態陣列在容量不足時會進行記憶體重新配置 (relocation),將所有資料搬移到一個新的、更大的記憶體區塊。然而,這個重新配置的動作並不會改變動態陣列在完成配置後,其內部元素仍然是連續儲存的事實。一旦新的記憶體區塊被分配並資料搬移完成,對
D.data[i]的存取仍然是 時間。記憶體重新配置只影響陣列本身的基底位址,不影響其內部元素的隨機存取特性。 - 結論: 此敘述不正確。動態陣列仍然適合隨機存取。
B. DArray can only be allocated in the heap memory due to its dynamic memory nature.
- 說明: 動態陣列的核心特性是其大小可以動態調整。這意味著其底層的資料儲存區塊 (即
D.data指向的記憶體) 必須在程式執行時動態分配和釋放。在 C/C++ 等語言中,這種動態記憶體分配通常發生在堆積 (heap) 記憶體上 (例如使用malloc或new)。 - 相較之下,堆疊 (stack) 記憶體用於儲存局部變數和函數呼叫資訊,其大小在編譯時或函數進入時就已固定,不允許在執行時動態改變大小。因此,動態陣列的底層資料儲存區塊必須在堆積上分配,才能實現其動態調整大小的功能。
- 然而,如果嚴格解釋「DArray」是指整個動態陣列物件 (包含
D.data指標、D.size和D.capacity等屬性),那麼這個物件本身是可以被宣告在堆疊上的 (例如DArray D;)。但其內部指向實際資料的指標D.data仍需指向堆積記憶體。 - 鑑於題目強調「dynamic memory nature」,通常是指其核心的資料儲存區塊。但「only」這個詞語使得此選項在嚴格語義上可能存在爭議。不過,在資料結構的語境中,動態陣列的「動態」特性確實依賴於堆積記憶體。
- 結論: 此敘述在一般理解下是正確的,但若嚴格區分物件本身與其底層資料儲存,則「only」可能不夠精確。
C. If ResizeA(D) is considered, the amortized time complexity of Insert(D, x) is O(1).
- 說明:
ResizeA(D)策略是每次將D.capacity增加一個常數 (例如 10)。我們使用聚合分析法 (aggregate analysis) 來計算 次Insert操作的總成本。 - 假設容量每次增加 。初始容量為 1。
- 當
D.size達到D.capacity時,會觸發Resize。假設容量從 增加到 ,則需要複製 個元素,成本為 。 - 考慮從空陣列開始插入 個元素。
Resize會在容量達到 時發生,直到容量至少為 。 - 總複製成本約為 ,其中 ,所以 。
- 這個求和是一個等差數列,其和約為 。
- 因此,總複製成本為 。每次插入操作本身還有 的成本。
- 總成本為 。
- 攤還時間複雜度為 總成本 / 操作次數 。
- 結論: 此敘述不正確。攤還時間複雜度為 。
D. If ResizeB(D) is considered, the amortized time complexity of Insert(D, x) is O(1).
- 說明:
ResizeB(D)策略是每次將D.capacity加倍。我們使用聚合分析法來計算 次Insert操作的總成本。 - 假設容量每次加倍。初始容量為 1。
- 當
D.size達到D.capacity時,會觸發Resize。假設容量從 加倍到 ,則需要複製 個元素,成本為 。 - 考慮從空陣列開始插入 個元素。
第 4 題10 分
Consider a hash function h that maps numerous keys into an array A, indexed from 0 to n-1. The concern is that excessive collisions arising from the hashed keys can potentially cause inefficiency within the hash table. The following pseudocode, while not complete, implements a function that utilizes the divide-and-conquer strategy to identify the case where strictly more than half of the keys share the same hash value. The function takes the hash h and the subarray A with the index range from low to high as input and returns the majority hash value shared by over ⌊(high - low + 1)/2⌋ keys. If the keys stored in the subarray A[low...high] do not have such a majority hash value, the function returns -1.
1: function FindMajorityHashValue(h, A, low, high)
2: if low = high then return h(A[low]) end if
3: mid ← ⌊(low + high)/2⌋
4: leftMajority ← FindMajorityHashValue(h, A, low, mid)
5: rightMajority ← FindMajorityHashValue(h, A, mid + 1, high)
6: leftCount ← CountElement(A, low, high, leftMajority)
7: rightCount ← CountElement(A, low, high, rightMajority)
8: [BLANK BOX]
9: end function
In the pseudocode, CountElement(A, low, high, val) calculates and returns the count of keys in the subarray A[low...high] whose hashed values are equal to the given val. Please select the correct description(s) below.
A. (b) and (f) are the same.
B. (c), (d), and (e) are all distinct.
登入後即可作答並保存紀錄。
這題考查的核心觀念是分治法 (Divide and Conquer) 演算法的設計與時間複雜度分析,特別是應用於尋找陣列中多數元素 (Majority Element) 的問題。多數元素指的是在一個序列中出現次數嚴格超過一半的元素。此外,也考驗了對遞迴關係式 (Recurrence Relation) 的建立與主定理 (Master Theorem) 的應用,以分析演算法的時間複雜度。
完整解題過程
首先,我們來分析 FindMajorityHashValue 函式的邏輯。這個函式採用分治策略來尋找多數雜湊值。
-
基本情況 (Base Case):如果
low = high,表示子陣列只有一個元素,那麼這個元素的雜湊值就是該子陣列的「多數」雜湊值(因為它出現了 1 次,而長度為 1 的子陣列,多數條件是> 1/2,即至少 1 次)。 -
遞迴步驟 (Recursive Step):
- 將子陣列
A[low..high]分成左右兩半:A[low..mid]和A[mid+1..high]。 - 遞迴呼叫
FindMajorityHashValue找出左右兩半的多數雜湊值候選leftMajority和rightMajority。 - 關鍵邏輯:如果整個陣列
A[low..high]存在一個多數雜湊值X,那麼X必須是leftMajority或rightMajority之一(如果它們不是 -1)。- 證明:假設
X是A[low..high]的多數雜湊值,但它既不是A[low..mid]的多數雜湊值,也不是A[mid+1..high]的多數雜湊值。- 令子陣列
A[low..high]的長度為 。 - 左半部分
A[low..mid]的長度為 。 - 右半部分
A[mid+1..high]的長度為 。 - 由於
X是A[low..high]的多數雜湊值,所以 。 - 如果
X不是A[low..mid]的多數雜湊值,則 。 - 如果
X不是A[mid+1..high]的多數雜湊值,則 。 - 將兩者相加:
- 這與 矛盾。因此,如果
A[low..high]存在多數雜湊值,它必然是leftMajority或rightMajority之一(如果它們不是 -1)。
- 令子陣列
- 證明:假設
- 因此,函式只需要檢查這兩個候選值
leftMajority和rightMajority是否在整個A[low..high]範圍內滿足多數條件即可。這就是為什麼第 7 和 8 行的CountElement呼叫是針對A[low..high]整個範圍進行計數的原因。
- 將子陣列
接下來,我們逐一分析每個選項:
(A) If leftMajority = rightMajority = -1, A[low..high] may still have a majority hash value.
- 分析:根據上述證明,如果
leftMajority = -1,表示A[low..mid]中不存在多數雜湊值,即對於任何值v,其在A[low..mid]中的出現次數 。 - 同理,如果
rightMajority = -1,表示A[mid+1..high]中不存在多數雜湊值,即對於任何值v,其在A[mid+1..high]中的出現次數 。 - 如果
leftMajority = rightMajority = -1,那麼對於任何值v,其在A[low..high]中的總出現次數為:
- 這表示任何值
v在A[low..high]中的出現次數都不會嚴格超過一半。因此,A[low..high]不可能有多數雜湊值。 - 結論:選項 (A) 為錯誤。
**(B) If A[low..high] has a majority hash value and rightMajority = -1, the function should retur
第 5 題10 分
A Binary Search Tree (abbreviated as BST) is a tree structure comprised of nodes that maintain a specific order among their keys. Given a single node x and two BSTs L and R, in which l.key < x.key < r.key for all nodes l ∈ L and r ∈ R, the objective is to design a Join(L, x, R) function that integrates the given input into a unified BST T with the nodes L ∪ {x} ∪ R. Be aware that AVL and Red-Black trees are specific types of BSTs. Given the constraint that T, L, and R must share the same type, they are required to be either all BSTs, all AVL trees, or all Red-Black trees.
The Join(L, x, R) function is implemented with the steps: (1) selecting a subtree T' from either L or R, where a subtree is defined as potentially being empty, a portion, or the entire tree, (2) detaching T', (3) attaching the tree rooted at x to the former parent of T'. The modified tree is then returned as T. If T' has no former parent, the tree rooted at x is simply returned as T. The following figure demonstrates an example result of Join(L1, x1, R1), where the value represents the key of the node. Inside a circle, the value represents the key of the node.
Please note that almost all steps, except for (1), have been finalized — there could be multiple ways to choose T' in (1). The tree returned from Join(L, x, R) may not be unique. Additionally, unlike AVL or Red-Black trees, Join does not perform re-coloring and re-balancing. Consider the following following arguments for brevity. All nil nodes (considered in red-black trees) are omitted for brevity.
A. If no additional balance is required for L2 and R2, i.e., both L2 and R2 are BSTs, there are 6 possible tree shapes that could be returned from Join(L2, x2, R2).
登入後即可作答並保存紀錄。
核心觀念
必須維持 BST 的大小順序,因此從 選 時,只能沿 的最右路徑選取;從 選時,只能沿 的最左路徑選取,路徑末端的空子樹也可選。AVL 樹要求每個節點左右子樹高度差至多為 ;紅黑樹則要求根與 NIL 葉為黑色、沒有紅紅相鄰,且每條根至 NIL 的路徑黑高相同。
解題方法
圖中 是根節點 、左右子節點 ;。 以 為根,左子樹根為 (其左右子樹根為 ,且 的右子為 、 的左子為 1311、1511121514、161617$)。
合法的 選擇共有七個:在 可選根 、根 ,或 的空右子樹;在 可選根 、根 、根 ,或 的空左子樹。選根 與選根 都會得到以 為根、 與 分居左右的相同形狀,因此七種選擇只形成六種樹形。
選項分析
A. 正確。 七種合法選擇中,選整棵 或整棵 的結果相同,其餘選擇各形成不同樹形,故共有六種。
B. 錯誤。 都是 AVL 樹,但至少有兩種 Join 結果仍為 AVL 樹。以葉節點高度 計, 高度為 ,根為 的子樹高度為 ,根為 的子樹高度為 ,根為 的子樹高度為 。
- 選根 為 : 的左右子樹高度為 ,故 的高度為 ;根 的左右子樹高度為 。
- 選根 為 : 的左右子樹高度為 ,故 的高度為 ;根 的左右子樹高度為 ,根 的左右子樹高度則為 $3、3
第 6 題5 分
We want to multiply a sequence of matrices M1, ..., Mn with the minimum number of multiplications. Since the matrix multiplication is associative, we can parenthesize the multiplication in all possible orders. Let m_ij be the minimum number of multiplications to multiply M_i, ..., M_j. We can derive a recursion of m_ij, where r_i and c_i are the numbers of rows and columns of the matrix M_i respectively.
(1)
Now consider m_{s,s+k}, 1 < s < s+k < n. For given s and k, let x be the number of m_ij's that have m_{s,s+k} at the right hand side of Equation 1, and let y be the number of different m's that are at the right-hand side of Equation 1, and let y be the number of different m's that are at the right-hand side of Equation 1 when i = s and j = s+k. What is the approximate value of x + y?
A. s(n-k/2)
B. n + k
C. (n-s)(n-s)(n-s-k)
D. (n/2) + (n/2)
E. (n-k/2) + (k/2)
登入後即可作答並保存紀錄。
這題考驗考生對動態規劃經典問題「矩陣鏈乘法 (Matrix Chain Multiplication)」的遞迴關係式理解,並要求計算特定條件下遞迴式中相關項的數量。
核心觀念:
- 矩陣鏈乘法遞迴關係式: 表示計算矩陣 所需的最小乘法次數。其遞迴關係式為 。這個關係式適用於 的情況。
- 基本情況 (Base Cases):
- (單一矩陣不需要乘法)。
- (兩個矩陣相乘只需要一次乘法)。
- 計數問題分析:根據題目給定的 ,計算兩個數量 和 。
完整解題過程:
題目給定的條件是 。這意味著:
- (因為 )
- (因為 )
- (因為 )
- 對於遞迴關係式 ,其適用條件是 。因此,對於 ,我們必須有 ,即 。如果 ,則 是一個基本情況,不使用此遞迴式。然而,我們將證明即使 ,最終的公式 仍然成立。
第一部分:計算
是當 且 時,在 Equation 1 的右側出現的不同 項的數量。
考慮 的遞迴式:
其中 是分割點。
的可能取值範圍是 。
的數量為 個。
對於每一個 值,右側會出現兩個 項: 和 。
-
項的集合:
當 取 時,這些項分別是:
。
這些項共有 個,且它們都是不同的 (因為第二個索引不同)。 -
項的集合:
當 取 時,這些項分別是:
。
這些項共有 個,且它們都是不同的 (因為第一個索引不同)。 -
判斷是否有重複:
第一個集合中的所有項的起始索引都是 。
第二個集合中的所有項的起始索引都是 或更大 (因為 )。
由於 ,這兩個集合中的所有項都是不同的。
因此, 的總數是兩個集合的項數之和:
這個公式對於 都成立。如果 ,則 ,因為 沒有整數 。
第二部分:計算
是有多少個 項在其遞迴計算的右側包含 。
這意味著 必須是某個 計算中的 或 。
第 7 題5 分
When we compute all m_ij's with Equation 1, we must follow an order of i and j so that the m's on the right-hand side are all known when we compute m_ij. Please select all the correct orders in the following choices.
A. decreasing order of i + j
B. increasing order of i + j
C. increasing order of (i - j)^2
D. decreasing order of (i - j)^3
E. increasing order of |(i + j)(i - j)|
登入後即可作答並保存紀錄。
本題考查的核心觀念是動態規劃 (Dynamic Programming) 的計算順序。在解決具有重疊子問題 (overlapping subproblems) 和最佳子結構 (optimal substructure) 的問題時,動態規劃通常會將問題分解為更小的子問題,並依序解決這些子問題,以確保當計算一個較大的問題時,其所需的子問題結果都已經備妥。
對於矩陣鏈乘法問題的遞迴關係式:
其中 代表計算從第 個矩陣到第 個矩陣連乘的最小乘法次數。
觀察遞迴關係式,要計算 的值,我們需要 和 的值。
- 代表的矩陣鏈長度 (span 或 length) 為 。
- 代表的矩陣鏈長度為 。
- 代表的矩陣鏈長度為 。
由於 ,我們可以推斷出:
- (因為 )
- (因為 )
這表示 和 都是比 更短的矩陣鏈乘法子問題。因此,動態規劃的計算順序必須確保在計算任何一個 之前,所有比它短的子問題 (即 和 ) 都已經被計算出來。最直接且常見的順序就是依據矩陣鏈的長度 (或跨度) 遞增計算。
現在我們來分析每個選項:
A. decreasing order of
假設我們依 的遞減順序計算。考慮 ,其 。
它可能需要 (當 時,需要 和 ; 的 )。
由於 的 值 (5) 大於 的 值 (4),在遞減順序中 會在 之前計算。這部分沒問題。
但它也可能需要 (當 時,需要 和 ; 的 )。
在遞減順序中 的 值 (3) 小於 的 值 (4),這表示 會在 之後計算,但 卻需要 的結果。這會導致錯誤。
因此,選項 A 不正確。
B. increasing order of
假設我們依 的遞增順序計算。考慮 ,其 。
它需要 (當 時,需要 和 ;
第 8 題5 分
We define the height of a tree to be the maximum number of edges from the root to a leaf. We also define the level of a node v, denoted as l(v) to be the height of the subtree rooted at v. Which of the following descriptions is correct?
A. If v is a leaf, then l(v) = 1.
B. If v is an internal node, l(v) = max_{v∈S} l(s), where S is the set of children of v.
C. We can compute l(v) by starting a breadth-first-search (BFS) from v, traversing all nodes of the subtree rooted at v, and computing the maximum distance to a leaf as l(v). Since there are no more than n v's and each BFS takes O(n) time, the total time complexity is O(n^2).
D. We can compute the levels for all nodes by a depth-first-search (DFS) starting from the root of T. That is, we can compute the level of an internal node v after we compute the l values of all children of v.
E. Since there are n tree nodes to visit, the DFS from the root takes O(n) time.
登入後即可作答並保存紀錄。
同學你好,我是你們的資深補教名師。這題主要在考驗同學對樹高 (height) 與節點深度 (level) 這些基本樹狀結構概念的理解,以及如何利用常見的圖形遍歷演算法(如 BFS 和 DFS)來計算這些屬性,同時評估其時間複雜度。理解這些定義的細微差異以及不同演算法的適用性與效率,是解題的關鍵。
解題過程:
首先,我們明確題目給出的定義:
- 樹高 (height of a tree):從根節點到任一葉節點的最大邊數 (maximum number of edges from the root to a leaf)。根據此定義,一個只有單一節點的樹(該節點既是根也是葉)其高度為 0。
- 節點 的 level ():以 為根的子樹的高度 (height of the subtree rooted at )。
接下來,我們逐一分析每個選項:
A. If v is a leaf, then l(v) = 1.
- 根據定義,如果 是一個葉節點,則以 為根的子樹只包含 本身。
- 該子樹的高度是從 到它自身(作為葉節點)的最大邊數,也就是 0 條邊。
- 因此,若 是葉節點,則 。
- 此敘述與定義不符。
- 【答案】:錯誤
B. If v is an internal node, l(v) = max{l(s) | s is the set of children of v}.
- 若 是一個內部節點,則以 為根的子樹的高度,應該是 到其任何一個子代葉節點的最長路徑的邊數。
- 這條最長路徑必然會經過 的某個子節點 。從 到 有 1 條邊。
- 從 到其子樹內的葉節點的最長路徑邊數是 。
- 因此,以 為根的子樹的高度應該是 。
- 此敘述缺少了從 到其子節點的那 1 條邊。
- 【答案】:錯誤
C. We can compute l(v) by starting a breadth-first-search (BFS) from v, traversing all nodes of the subtree rooted at v, and computing the maximum distance to a leaf as l(v). Since there are no more than n v's and each BFS takes O(n) time, the total time complexity is O(n^2).
- 方法正確性:從節點 開始進行廣度優先搜尋 (BFS),確實可以找到從 到其子樹中所有節點的最短距離。而 正是以 為根的子樹中,從 到任一葉節點的最大距離(邊數)。因此,透過 BFS 找到所有葉節點並取其與 之間的最大距離,確實能計算出 。
- 時間複雜度分析:
- 對於樹中的單一節點 ,在其子樹上執行一次 BFS 的時間複雜度為 ,其中 是 子樹中的節點數, 是 子樹中的邊數。由於是樹, ,所以是 。
- 在最壞情況下,如果 是整棵樹的根,那麼 (總節點數)。因此,單次 BFS 可能需要 時間。
- 如果要計算所有 個節點的 值,並且對每個 都執行一次 BFS,則總時間複雜度為 。
- 此敘述在方法和時間複雜度分析上均正確。
- 【答案】:正確
第 9 題5 分
We have a binary tree T and for every node v ∈ T, we want to compute the new height if we select v as the new root. First, the height of the subtree of v is still l(v). Second, the height of the tree after making v the new root is max(l(v), r(v)). We define this distance as r(v).
A. The new tree after selecting a new root is always a binary tree.
B. The height of the tree after making v the new root is max(l(v), r(v)).
C. We can compute r(v) for all tree node v's in a top-down manner. We assume that the r value of v's parent in T is known, so v only needs to consider the r value of its parent and the l value of its sibling in T, in order to compute its own r.
D. The r value of the root of T is 1.
E. We can compute the r values for all nodes in O(n) time.
登入後即可作答並保存紀錄。
本題考查的核心觀念是二元樹的性質、樹的高度計算,以及「樹的重新紮根 (re-rooting)」技巧,這是一種常見的樹形動態規劃 (Tree DP) 問題,通常用於計算每個節點作為根時,樹的某些性質。
完整解題過程
題目定義了兩個值:
- : 節點 在原始樹 中,其子樹的高度。根據資料結構與演算法中樹高的標準定義,通常是指從 到其子樹中最遠葉節點的邊數。若葉節點的高度為 0,則 ,對於葉節點 則 。
- : 節點 作為新根時,從 向上走到其父節點,再向下走到最遠葉節點的距離。這代表了從 往上走,進入原始樹中不屬於 子樹的「其他部分」所能達到的最遠距離。
當 被選為新根時,新樹的高度將是從 出發,到新樹中最遠葉節點的距離。這個最遠路徑可以有兩種情況:
- 路徑向下進入 原始的子樹。最長路徑長度為 。
- 路徑向上走到 的原始父節點,然後再向下進入原始樹中不屬於 子樹的任何其他部分。最長路徑長度為 。
因此,新樹的高度將是 。
現在我們逐一分析每個選項:
(A) The new tree after selecting a new root is always a binary tree.
- 分析: 在原始二元樹中,每個節點最多有兩個子節點。當我們將節點 重新紮根為新根時,它原始的左子節點和右子節點(如果存在)仍然是它的子節點。此外,如果 在原始樹中有一個父節點 ,那麼當 成為新根時, 將成為 的一個子節點。
- 如果 在原始樹中同時擁有左子節點、右子節點和父節點,那麼當 成為新根時,它將會有三個子節點。這違反了二元樹中每個節點最多只能有兩個子節點的定義。
- 結論: 該敘述不正確。
(B) The height of the tree after making v the new root is max(l(v), r(v)).
- 分析: 如前所述,當 成為新根時,從 到新樹中最遠葉節點的路徑有兩種可能性:
- 路徑向下進入 原始的子樹,其最長距離為 。
- 路徑向上經過 的原始父節點,然後進入原始樹中不屬於 子樹的其他部分,其最長距離為 。
- 這兩種情況涵蓋了所有從新根 到葉節點的可能路徑。因此,新樹的總高度就是這兩種最長路徑中的最大值。
- 結論: 該敘述正確。
(C) We can compute r(v) for all tree node v's in a top-down manner. We assume that the r value of v's parent in T is known, so v only needs to consider the value of its parent and the l value of its sibling in T, in order to compute its own r.
- 分析: 計算 是一個典型的樹形動態規劃問題,通常採用兩次深度優先搜尋 (DFS) 來解決。
- 第一次 DFS (Post-order traversal,由下而上): 計算所有節點的 值。對於每個節點 ,其 值取決於其子節點的 值。
- 若 是葉節點,。
- 第一次 DFS (Post-order traversal,由下而上): 計算所有節點的 值。對於每個節點 ,其 值取決於其子節點的 值。
第 10 題5 分
Consider a sequence of numbers (v1, ..., vn). Now we remove k numbers from the sequence so that we have k+1 non-empty segments of numbers. For example, consider (2, 3, 8, 1, 4). If we remove 8 then we have two segments (2, 3) and (1, 4). Now we want to minimize the maximum sum of numbers of a segment. Let m(1, n, k) be the answer, then what is the correct recursion for m when 1 ≤ i < j ≤ n and 0 < k ≤ j - i - 1?
A. m(i, j, k) = min_{x=i}^{j-1} max(∑{y=i}^{x} v_y, m(i, x - k - 1))
B. m(i, j, k) = min{x=i+1}^{j-1} max(∑{y=i}^{x-1} v_y, m(i, x - 1, k - 1))
C. m(i, j, k) = min{x=i+1}^{j-1} max(m(x + 1, j, k - 1), ∑{y=i}^{x-1} v_y)
D. m(i, j, k) = min{v+w=k-1, v,w≥0} min_{x=i+1}^{j-1} max(m(x - 1, v), m(x + 1, j, w))
E. m(i, j, k) = min_{v+w=k-1, v,w≥0} min_{x=i}^{j} max(m(i, x, v), m(x, j, w))
登入後即可作答並保存紀錄。
這題考驗的核心觀念是動態規劃 (Dynamic Programming),特別是處理序列分割 (sequence partitioning) 問題,並在分割過程中分配有限資源(此處為移除數字的數量)的技巧。這類問題通常會定義一個狀態 代表子問題的解,然後透過枚舉分割點來遞迴地求解。
完整解題過程:
-
理解問題定義:
我們有一個數字序列 。目標是從中移除 個數字,使得剩下的數字形成 個非空連續區段 (segments)。我們希望最小化這 個區段中,所有區段和的最大值。
被定義為處理子序列 時,移除 個數字後所能得到的最小最大區段和。 -
分析基礎情況 (Base Case):
當 時,表示不移除任何數字。此時,整個子序列 形成一個單一區段。因此,其區段和就是所有數字的和。
如果 ,表示這是一個空序列,其區段和應為 (或在某些情況下定義為 ,但對於最大和問題,0 更合理)。 -
推導遞迴關係 (Recurrence Relation):
考慮如何計算 當 時。我們需要移除 個數字。
核心思想是:我們必須在某處進行一次「分割」,而這次分割會消耗掉一個「移除」的額度。
假設我們選擇在 和 之間進行分割。這表示 會是左半部分序列的最後一個元素,而 會是右半部分序列的第一個元素。這次分割本身被視為消耗了 個移除額度中的一個。
因此,我們剩下 個移除額度,需要分配給左半部分 和右半部分 。- 左半部分 需要進行 次移除。
- 右半部分 需要進行 次移除。
- 總共的移除次數為 ,所以 。
- 和 都必須是非負整數 ()。
對於一個特定的分割點 和移除額度分配 ,其結果是左右兩部分各自的最小最大區段和中的較大者:。
由於我們要最小化這個最大區段和,我們需要遍歷所有可能的分割點 以及所有可能的移除額度分配 ,並取其中的最小值。分割點 的範圍:
代表左半部分序列的結束索引。- 左半部分至少要包含一個元素,所以 。
第 11 題5 分
Which of the following descriptions is true for the previous problem?
A. We can always find an optimal solution that removes one of the largest v.
B. We can always find an optimal solution that does not remove the largest v.
C. The initial value of m(i, i, 0) is n.
D. The initial value for m(i, j, k) when k > (j - i)/2 is 0.
E. The initial value for m(i, i + 2.1), 1 ≤ i ≤ n - 2 is max(v_i, v_{i+2}).
登入後即可作答並保存紀錄。
本題考查的核心觀念是動態規劃 (Dynamic Programming) 問題的性質與邊界條件 (Base Cases)。具體來說,是針對「從序列中移除 個數字,使剩餘的 個數字形成 個非空連續子序列,並最小化這些子序列中最大和」這個問題的性質進行判斷。
完整解題過程:
首先,我們需要明確問題 10 中 的定義。根據題目描述,對於子序列 ,我們移除 個數字,使其形成 個非空連續子序列。 是在這種情況下,所有可能移除方案中,所形成 個子序列的最大和的最小值。
假設我們移除了 個數字 ,其中 。
這些移除的數字將原始子序列 分割成 個連續子序列:
...
根據題目要求,所有這些 個子序列都必須是「非空」的。這對移除的索引 施加了以下限制:
- 第一個子序列 非空:。
- 最後一個子序列 非空:。
- 中間的子序列 非空:。
接下來,我們逐一分析每個選項:
A. We can always find an optimal solution that removes one of the largest .
(我們總能找到一個最佳解,其中移除了其中一個最大的 。)
這個說法是錯誤的。我們可以構造一個反例:
考慮序列 ,其中 ,我們要移除 個數字。
根據上述限制,可移除的索引 必須滿足 ,即 。
序列中最大的數字是 (即 和 )。
- 如果移除 (最大的 ):形成的子序列是 和 ,即 和 。最大和為 。
- 如果移除 (最大的 ):形成的子序列是 和 ,即 和 。最大和為 。
- 如果移除 (非最大的 ):形成的子序列是 和 ,即 和 。最大和為 。
在此例中,最佳解是移除 ,其最大和為 。而移除最大的 (無論是 或 ) 都會得到 ,並非最佳解。因此,此敘述為假。
B. We can always find an optimal solution that does not remove one of the smallest .
(我們總能找到一個最佳解,其中沒有移除任何一個最小的 。)
這個說法也是錯誤的。我們可以構造一個反例:
考慮序列 ,其中 ,我們要移除 個數字。
根據上述限制,可移除的索引 必須滿足 ,即 。
第 12 題5 分
Consider a directed acyclic graph G = (V, E) of n tasks where every node is a task and every edge is a dependency. If there is an edge from a task v to another task r that means we need to finish v before starting w. We have p processors of the same capability and every processor can finish any task in one time step. Also, a schedule needs to respect the dependency of edges.
A. For every positive integer i, |{v | s(v) ≤ i}| ≤ p.
B. If there is a path (v1, ..., vk) in G, then s(v_k) < s(v_j) for 1 ≤ j ≤ k.
C. The number of time steps required is at least min(⌈n/p⌉, L), where L is the number of tasks along the longest path in G.
D. Without loss of generality, we can always assume s(v) = 1 for all v's without incoming edges.
E. If the number of processors is infinite, then we can finish all tasks in L time steps, where L is the number of tasks along the longest path in G.
登入後即可作答並保存紀錄。
這題考驗的是對有向無環圖 (DAG) 上的任務排程基本概念的理解,特別是關於任務依賴性、處理器限制以及關鍵路徑的影響。
完整詳解
這題的核心觀念是理解在有向無環圖 (DAG) 中,任務排程如何受到任務依賴性 (dependency) 和處理器數量 (processor count) 的限制。它結合了圖論中的拓撲排序 (topological sort) 和排程理論中的關鍵路徑 (critical path) 概念。
我們逐一分析每個選項:
A. For every positive integer i, |{v | s(v) ≤ i}| ≤ p.
這個敘述表示「對於任何正整數時間步 ,在時間步 或之前完成的任務總數不超過 個」。
這與題目中「系統在一個時間步內最多只能處理 個任務」的定義不符。題目中的限制是指在單一時間步 內,正在執行的任務數量不能超過 個,即 。
如果 ,這代表任務 在時間 中的某個時間步完成。累積到時間 完成的任務總數可以遠大於 。例如,如果有 個任務,且 ,那麼在所有任務完成時(假設在時間 ),,而 可能遠大於 。
因此,選項 A 是錯誤的。
B. If there is a path in G, then .
題目定義:「如果從任務 到任務 有一條邊,表示我們需要先完成 才能開始 」。這直接意味著任務 的排程時間必須早於任務 的排程時間,即 。
如果圖 中存在一條路徑 ,這表示存在一系列的依賴關係:, , , 。
根據依賴性規則,我們有:
將這些不等式串聯起來,我們得到 。
因此,選項 B 是正確的。
C. The number of time steps required is at least , where L is the number of tasks along the longest path in G.
設總共所需的時間步數為 。
我們有兩個主要的下界 (lower bound):
- 處理器限制的下界:總共有 個任務,每個任務需要 1 個時間單位。總工作量為 個時間單位。如果有 個處理器,在最理想的情況下,所有處理器都持續忙碌,則完成所有任務至少需要 個時間步。
- 依賴性限制的下界 (關鍵路徑): 是圖 中最長路徑上的任務數量。
第 13 題30 分
A vertex cover of an undirected graph G = (V, E) is a subset V' ⊆ V such that if (u, v) ∈ E, then either u ∈ V' or v ∈ V' (or both). The size of a vertex cover is defined as the number of vertices in it. The vertex-cover problem is to find a vertex cover of minimum size in a given undirected graph. It has been shown to be NP-hard, thus we cannot find a polynomial-time algorithm for solving it exactly unless NP = P. Fortunately, some polynomial-time approximation algorithms have been proposed for solving the vertex-cover problem.
The following two approximation algorithms take as input an undirected graph and compute a vertex cover for it. Initially, all edges in the graph are uncovered for both Algorithm VC-Arbitrary and Algorithm VC-Max-Degree. Once a vertex v is put into the cover, all edges incident on v are covered and removed.
Algorithm VC-Arbitrary picks an arbitrary uncovered edge (u, v), puts both u and v into the cover, throws out all edges incident on either u or v, and repeats the process until there are no uncovered edges left.
Algorithm VC-Max-Degree picks a vertex v that covers the most of the uncovered edges, puts v into the cover, throws out all edges incident on v, and repeats the process until there are no uncovered edges left.
(a) (10 points) Give an example for which Algorithm VC-Arbitrary yields a solution that is at least double the size of a minimum-size vertex cover. Give another example for which Algorithm VC-Max-Degree will definitely yield a solution with the size more than that of a minimum-size vertex cover no matter how it breaks the tie. Each example should contain no more than ten vertices. You have to justify your solution by showing the vertex cover found by the algorithm and its corresponding minimum-size vertex cover.
(b) (10 points) Prove or disprove that Algorithm VC-Arbitrary has a smaller ratio bound than Algorithm VC-Max-Degree. The ratio bounds in your proof or disproof should be as tight as possible.
(c) (10 points) In the weighted vertex-cover problem, you are given an undirected graph G = (V, E) and a weight w(v) for each vertex v ∈ V, and the objective is to find a vertex cover (covering all edges in E) of minimum total weight. In other words, the goal is to find a vertex cover C of G such that Σ_{v∈C} w(v) is minimized among all possible vertex covers of G. You are required to formulate the weighted vertex cover problem as an integer linear program.
登入後即可作答並保存紀錄。
本題主要考驗考生對於圖論中「頂點覆蓋問題 (Vertex Cover Problem)」的理解,特別是兩種近似演算法 (Approximation Algorithms) 的特性與效能分析,以及如何將加權頂點覆蓋問題 (Weighted Vertex Cover Problem) 建模為整數線性規劃 (Integer Linear Program, ILP)。這是一道綜合性題目,涵蓋了演算法設計、分析與數學建模等多個面向。
(a) 舉例說明兩種近似演算法的表現
Algorithm VC-Arbitrary 的例子
目標: 找出一個例子,使得 Algorithm VC-Arbitrary 得到的解至少是最小頂點覆蓋的兩倍大。
圖例: 考慮一個包含 5 個頂點的簡單路徑圖 。
最小頂點覆蓋 (Minimum-size Vertex Cover, ):
我們可以選擇 。
- 覆蓋了邊 和 。
- 覆蓋了邊 和 。
所有邊都被覆蓋。因此,最小頂點覆蓋的大小為 。
Algorithm VC-Arbitrary 找到的頂點覆蓋 ():
- 步驟 1: 演算法任意選擇一條未覆蓋的邊。假設選擇邊 。
將 和 加入覆蓋集合 。此時 。
移除所有與 或 相連的邊: 和 。
剩餘未覆蓋的邊:。 - 步驟 2: 演算法再次選擇一條未覆蓋的邊。假設選擇邊 。
將 和 加入覆蓋集合 。此時 。
移除所有與 或 相連的邊: 和 。
剩餘未覆蓋的邊:。 - 終止: 沒有未覆蓋的邊,演算法終止。
Algorithm VC-Arbitrary 找到的頂點覆蓋為 ,其大小為 。
結果:
,而 。因此,VC-Arbitrary 的解是最小解的兩倍大 ()。
Algorithm VC-Max-Degree 的例子
目標: 找出一個例子,使得 Algorithm VC-Max-Degree 得到的解一定會比最小頂點覆蓋大,無論如何打破平手。
圖例: 考慮一個包含 7 個頂點的圖 。
這個圖可以想像成一個中心頂點 連接到三個獨立的邊 的其中一個端點。
最小頂點覆蓋 ():
我們可以選擇 。
- 覆蓋了邊 和 。
- 覆蓋了邊 和 。
- 覆蓋了邊 和 。
所有邊都被覆蓋。因此,最小頂點覆蓋的大小為 。
Algorithm VC-Max-Degree 找到的頂點覆蓋 ():
- 初始階段: 計算所有頂點的度數。
(與 相連)
(與 相連)
(與 相連)
(與 相連)
(與 相連)
(與 相連)
(與 相連)
頂點 具有最高的度數 (3)。 - 步驟 1: 選擇頂點 (度數為 3)。將 加入覆蓋集合 。此時 。
移除所有與 相連的邊:。
剩餘未覆蓋的邊:。 - 步驟 2: 計算剩餘圖中頂點的度數。
(與 相連)
(與 相連)
(與 相連)
(與 相連)
(與 相連)
(與 相連)
所有剩餘頂點的度數均為 1。無論如何打破平手,演算法都會選擇一個度數為 1 的頂點。
假設選擇 。將 加入覆蓋集合 。此時 。
移除與 相連的邊:。
剩餘未覆蓋的邊:。 - 步驟 3: 再次選擇一個度數為 1 的頂點。假設選擇 。將 加入覆蓋集合 。此時 。
移除與 相連的邊:。
剩餘未覆蓋的邊:。 - 步驟 4: 再次選擇一個度數為 1 的頂點。假設選擇 。將 加入覆蓋集合 。此時 。
移除與 相連的邊:。
剩餘未覆蓋的邊:。 - 終止: 沒有未覆蓋的邊,演算法終止。
Algorithm VC-Max-Degree 找到的頂點覆蓋為 ,其大小為 。