109 年 國立中央大學資訊工程學系碩士班《資料結構與演算法》

📄 試題原卷 免費註冊後即可對照原始考卷 PDF免費註冊

第 1 題5 分

Consider the graph below. Which of the following is a DFS traversal sequence starting from node 1?

🖼️【此處有附圖,請對照原卷】

(A) 1,2,6,7,4,0,8,5,3,101,2,6,7,4,0,8,5,3,10
(B) 1,8,0,4,7,5,6,3,10,21,8,0,4,7,5,6,3,10,2
(C) 1,2,6,7,4,5,0,8,3,101,2,6,7,4,5,0,8,3,10
(D) 1,4,0,8,7,6,3,10,2,51,4,0,8,7,6,3,10,2,5

🖼️ 本題附圖:
第 1 題附圖
圖看不清楚?展開原卷第 1 頁核對
原卷第 1 頁

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

深度優先搜尋(DFS)會沿著尚未拜訪的鄰接頂點持續深入;只有目前頂點的所有鄰接頂點都已拜訪,才能回溯至上一層。

DFS 走訪序列只記錄各頂點「第一次被拜訪」的順序,不記錄回溯經過的頂點。因此,序列中連續出現的兩個頂點不一定直接相連。題目未指定鄰接頂點的選擇順序,所以同一張圖可以有多種合法的 DFS 序列。

解題方法

依原圖,這是無向圖,外圈的邊形成 1 ⁣− ⁣2 ⁣− ⁣10 ⁣− ⁣3 ⁣− ⁣6 ⁣− ⁣7 ⁣− ⁣4 ⁣− ⁣0 ⁣− ⁣8 ⁣− ⁣11\!-\!2\!-\!10\!-\!3\!-\!6\!-\!7\!-\!4\!-\!0\!-\!8\!-\!1,另外還有邊 2 ⁣− ⁣62\!-\!6、7 ⁣− ⁣57\!-\!5 與 1 ⁣− ⁣41\!-\!4,共 12 條邊。其中,55 只與 77 相連。

逐一模擬各選項:下一個頂點若是目前頂點尚未拜訪的鄰點,就向下深入;若需要回溯,則檢查沿途每個被離開的頂點是否已無未拜訪的鄰點。

以下以 →\to 表示首次拜訪,回溯則另外說明。

選項分析

  • (A) 正確:1,2,6,7,4,0,8,5,3,101,2,6,7,4,0,8,5,3,10

    先沿著
    1→2→6→7→4→0→81\to2\to6\to7\to4\to0\to8
    深入。到達 88 時,其鄰點 11、00 都已拜訪,可以依序經 00、44 回溯至 77,再拜訪 55。

    55 只有鄰點 77,因此回溯至 77;此時 77 的鄰點皆已拜訪,繼續回溯至 66,再沿著 6→3→106\to3\to10 深入。整個順序合法。

  • (B) 正確:1,8,0,4,7,5,6,3,10,21,8,0,4,7,5,6,3,10,2

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 2 題5 分

If a number 99 is inserted to the end of the Min-Heap below, and the heap is being reconstructed, which position will the 99 go?

Index012345678910
Content68151017162320221840

(A) A[0]A[0]
(B) A[1]A[1]
(C) A[2]A[2]
(D) A[5]A[5]

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

最小堆積(Min-Heap)是一棵完全二元樹,且每個節點的值都小於或等於其子節點。以從 00 開始的陣列表示時,索引 ii 的父節點索引為:

⌊i−12⌋\left\lfloor \frac{i-1}{2} \right\rfloor

插入新值時,先將它放在陣列末端,再沿父節點向上比較;若新值小於父節點,就交換,直到堆積順序成立。

解題方法

原陣列有 1111 個元素,因此新數字 99 先放在索引 1111。逐層向上比較:

  1. 索引 1111 的父節點索引為 ⌊(11−1)/2⌋=5\lfloor(11-1)/2\rfloor=5,該位置的值為 1616。因為 9<169<16,交換,99 移至索引 55。
  2. 索引 55 的父節點索引為 ⌊(5−1)/2⌋=2\lfloor(5-1)/2\rfloor=2,該位置的值為 1515。因為 9<159<15,交換,99 移至索引 22。
🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 3 題5 分

Given the following binary tree:

🖼️【此處有附圖,請對照原卷】

If we make this binary tree a threaded binary tree, what nodes are pointed to by threads of node 3?

(A) node 6
(B) node 2
(C) node 7
(D) node 9

🖼️ 本題附圖:
第 3 題附圖
圖看不清楚?展開原卷第 1 頁核對
原卷第 1 頁

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

中序線索二元樹會把原本未使用的左、右子指標改作「線索」,分別指向該節點的中序前驅與中序後繼。若某一側已有子節點,該側指標仍指向子節點,不改作線索。

解題方法

圖中與節點 3 有關的結構是:節點 6 的左子節點為 3,節點 3 的左子節點為 2,且節點 3 沒有右子節點。依中序走訪規則「左子樹、根、右子樹」,相關順序為節點 2、節點 3、節點 6。

因此,節點 3 的左指標指向子節點 2;右指標因沒有右子節點,改作中序後繼線索,指向節點 6。

選項分析

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 4 題5 分

What orderings are topological sortings of the graph below?

🖼️【此處有附圖,請對照原卷】

(A) 0,4,2,1,3,50,4,2,1,3,5
(B) 0,4,2,3,1,50,4,2,3,1,5
(C) 2,0,4,1,3,52,0,4,1,3,5
(D) 2,0,4,3,1,52,0,4,3,1,5

🖼️ 本題附圖:
第 4 題附圖
圖看不清楚?展開原卷第 1 頁核對
原卷第 1 頁

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

拓樸排序是有向無環圖中所有頂點的一種排列,使每條有向邊 u→vu\to v 的起點 uu 都排在終點 vv 前面。若以 pos⁡(v)\operatorname{pos}(v) 表示頂點 vv 在排列中的位置,必須滿足:

pos⁡(u)<pos⁡(v)對每條有向邊 u→v。\operatorname{pos}(u)<\operatorname{pos}(v) \qquad \text{對每條有向邊 }u\to v。

此限制也適用於間接路徑:若存在 u→⋯→vu\to\cdots\to v,則 uu 必須排在 vv 前面。因此,不能只因兩個頂點沒有直接連邊,就判定它們的順序可以互換。

解題方法

原圖共有六個頂點 0,1,2,3,4,50,1,2,3,4,5,依箭頭方向讀出八條有向邊:

0→4,0→1,2→3,2→1,4→3,4→1,4→5,3→5。0\to4,\quad 0\to1,\quad 2\to3,\quad 2\to1,\quad 4\to3,\quad 4\to1,\quad 4\to5,\quad 3\to5。

採用逐步移除入度為零的頂點的方法:入度為零代表所有前置限制都已滿足,可以排入下一個位置。

  1. 一開始可選 00 或 22:只有這兩個頂點的入度為零。
  2. 44 必須等 00 排入後才能選,因為有 0→40\to4。
  3. 11 與 33 都必須等 44、22 排入後才能選;其中 11 還要求 00 已排入,而 00 本來就必須先於 44。
  4. 55 必須等 44、33 排入後才能選,因為有 4→54\to5 與 3→53\to5。
🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 5 題5 分

Suppose that the result of the first partition step in quick sort is as follows:

3,9,1,14,20,24,22,213,9,1,14,20,24,22,21

Which of the following statements is true?

(A) The pivot is either 1414 or 2020.
(B) The pivot is 2020.
(C) Both 1414 and 2020 are pivots in the first partition.
(D) The pivot is 1414.

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

快速排序(quick sort)的第一次分割會選出一個樞紐(pivot),並將資料分成兩側:樞紐左側的元素不大於樞紐,右側的元素不小於樞紐。分割後,樞紐位於它的最終位置;但左右兩側的元素不必各自排序。

解題方法

依序檢查序列中的候選樞紐。若某個元素符合「左側元素全部不大於它,右側元素全部不小於它」,它就能是第一次分割的樞紐。

給定序列為:

3,9,1,14,20,24,22,213,9,1,14,20,24,22,21

檢查 1414:

  • 左側為 3,9,13,9,1,皆小於 1414。
  • 右側為 20,24,22,2120,24,22,21,皆大於 1414。

因此,1414 符合樞紐條件。

檢查 2020:

  • 左側為 3,9,1,143,9,1,14,皆小於 2020。
  • 右側為 24,22,2124,22,21,皆大於 2020。

因此,2020 也符合樞紐條件。兩側元素的排列不必有序,所以 24,22,2124,22,21 的順序不影響判斷。

選項分析

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 6 題5 分

Consider an empty hash table with 11 buckets, and each bucket has 2 slots. Suppose that linear probing is used to handle overflow, and the hash function is h(n)=n mod 11h(n)=n\bmod 11.

Now we sequentially insert the following numbers into the hash table:

6,16,22,44,53,24,45,7,74,4,109,78,126,16,22,44,53,24,45,7,74,4,109,78,12

What is the summation of the numbers in the full buckets of the hash table?

(A) 294
(B) 216
(C) 225
(D) 201

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

每個 bucket 有 2 個槽位。數字先放入雜湊函數指定的 bucket;若該 bucket 已滿,就依線性探測法往下一個 bucket 找,直到找到尚有空位的 bucket。

本題的雜湊函數為:

h(n)=n mod 11h(n)=n\bmod 11

「滿 bucket」指其中 2 個槽位都已放入數字。題目要加總所有滿 bucket 內的數字。

解題方法

依序計算每個數字的雜湊位置,並在碰撞時往後探測:

數字雜湊位置插入結果
66bucket 6:6
165bucket 5:16
220bucket 0:22
440bucket 0:22、44(滿)
539bucket 9:53
242bucket 2:24
451bucket 1:45
77bucket 7:7
748bucket 8:74
44bucket 4:4
10910bucket 10:109
781bucket 1:45、78(滿)
🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 7 題1 分

The postfix expression bcd+∗/aefg∗+∗bcd+*/aefg*+* is valid.

(A) True
(B) False

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

後序式(postfix expression)中,運算子寫在運算元之後。對二元運算子而言,從左至右掃描時:

  • 遇到運算元,就將它推入堆疊。
  • 遇到運算子,就必須從堆疊取出兩個運算元,完成運算後再將結果推回。
  • 掃描結束時,堆疊必須恰好剩下一個結果。

若遇到運算子時堆疊中的項目少於兩個,該後序式就不合法。

解題方法

依序掃描 bcd+∗/aefg∗+∗bcd+*/aefg*+*,括號內表示堆疊中的項目:

符號動作堆疊內容
bb推入運算元bb
cc推入運算元b, cb,\ c
dd推入運算元b, c, db,\ c,\ d
🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 8 題1 分

Consider an adjacency matrix on a directed graph. The row sum is the in-degree, while the column sum is the out-degree.

(A) True
(B) False

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

對有向圖的鄰接矩陣 AA,慣例是:若頂點 viv_i 有一條邊指向 vjv_j,則 Aij=1A_{ij}=1;沒有邊則 Aij=0A_{ij}=0。

因此:

  • 第 ii 列的總和 ∑jAij\sum_j A_{ij},計算從 viv_i 指出去的邊數,也就是 viv_i 的出度。
  • 第 jj 欄的總和 ∑iAij\sum_i A_{ij},計算指向 vjv_j 的邊數,也就是 vjv_j 的入度。

解題方法

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 9 題1 分

An arbitrary graph with G=(V,E)G=(V,E) and ∣E∣=∣V∣−1|E|=|V|-1 edges is a binary tree.

(A) True
(B) False

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

這題考圖的邊數能否單獨判定圖為樹,以及「二元樹」比一般樹多出的限制。

對含 nn 個頂點的無向圖,若圖連通且有 n−1n-1 條邊,則它是樹。反過來,樹也恰有 n−1n-1 條邊。但邊數條件本身不保證連通,也不保證符合二元樹的結構限制。

二元樹除了必須是樹,還要求以某個頂點為根後,每個頂點最多有兩個子節點。

解題方法

只要找出一個符合 ∣E∣=∣V∣−1|E|=|V|-1、卻不是二元樹的圖,就能否定題目中的「任意圖」這項主張。

例如,取一個三角形和一個孤立頂點:

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 10 題1 分

Depth-first search can be implemented by a stack.

(A) True
(B) False

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

深度優先搜尋(DFS)會沿著一條路徑持續往深處探索,直到無路可走時,再回到上一個分岔點繼續搜尋。這種「後進先出」的回溯順序,正好可以用堆疊(stack)實作。

遞迴版 DFS 會使用程式執行環境的呼叫堆疊記錄尚未完成的呼叫;迭代版 DFS 則可自行建立堆疊,記錄待探索的節點。

解題方法

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 11 題1 分

If V(G′)⊆V(G)V(G')\subseteq V(G) and E(G′)⊆E(G)E(G')\subseteq E(G), a graph G′G' is GG’s connected component.

(A) True
(B) False

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

圖 GG 的連通分量是 GG 的一個極大連通子圖:子圖中的任意兩個頂點彼此連通,而且不能再加入 GG 中其他頂點及相關邊,同時仍保持為連通子圖。

題目給出的 V(G′)⊆V(G)V(G')\subseteq V(G) 與 E(G′)⊆E(G)E(G')\subseteq E(G),只表示 G′G' 的頂點和邊來自 GG,也就是 G′G' 是 GG 的子圖。這些包含關係不足以保證 G′G' 是連通分量;還必須滿足連通性與極大性。

解題方法

檢查題目所述條件是否足以推出「連通分量」。只要找出一個符合頂點、邊包含關係,卻不是連通分量的子圖,就能否定此敘述。

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 1 題10 分

Suppose that two stacks, stack 0 and stack 1, are both mapped to array mem[MEMORY_SIZE]mem[\text{MEMORY\_SIZE}]. Algorithm PUSH adds an item into stack ii, where 0≤i<20\leq i<2, as long as the total number of items in these two stacks is less than MEMORY_SIZE−1\text{MEMORY\_SIZE}-1. Please complete algorithm PUSH.

Global variables:

int mem[MEMORY_SIZE]int\ mem[\text{MEMORY\_SIZE}]

int top[2]int\ top[2]

void PUSH(integer item,integer i)void\ PUSH(integer\ item, integer\ i)

{


}

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考兩個堆疊共用一個陣列的配置方式。堆疊 0 從陣列左端往右成長,堆疊 1 從右端往左成長,因此兩個堆疊能共用陣列空間。

題目未指定 top 的初始值與溢位處理方式;以下採用常見慣例:top[0] = -1、top[1] = MEMORY_SIZE,並在容量不足時回報溢位。

解題方法

top[0] 指向堆疊 0 最上方的元素;堆疊 1 則在推入前先將 top[1] 減一,再用它指向新元素。因此兩個堆疊目前的元素數分別為:

stack 0 元素數=top[0]+1\text{stack 0 元素數} = top[0] + 1 stack 1 元素數=MEMORY_SIZE−top[1]\text{stack 1 元素數} = \text{MEMORY\_SIZE} - top[1]

將兩者相加,先確認總元素數小於題目指定的 MEMORY_SIZE - 1,再依照堆疊編號更新對應的 top 並存入元素。

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 2 題5 分

Below is the algorithm that produces all permutations of a set with nn elements. Suppose the ii-th element of the set is stored in list[i]list[i]. Please fill the two blanks to complete the algorithm.

void perm(char∗list,int i,int n)void\ perm(char *list, int\ i, int\ n)

{

int j, temp;\quad int\ j,\ temp;

if (i==n) {\quad if\ (i==n)\ \{

\qquad For (j=1j=1; j≤nj\leq n; j++j++)

\qquad\quad Printf("%c", list[j]list[j]);

}\quad\}

else {\quad else\ \{

\qquad For (____) {

\qquad\quad SWAP(list[i]list[i], list[j]list[j], temptemp); /* swap list[i]list[i] and list[j]list[j] */


\qquad\quad SWAP(list[i]list[i], list[j]list[j], temptemp);

\qquad}

}\quad\}

}

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考「回溯法」產生排列。每一層遞迴決定一個位置要放哪個元素:

  • 位置 11 到 i−1i-1 已經決定。
  • 位置 ii 到 nn 尚未決定。
  • 將尚未決定的元素逐一換到位置 ii,再遞迴處理下一個位置。
  • 遞迴返回後,把交換還原,才能嘗試下一個候選元素。

當 i=ni=n 時,所有位置都已決定,輸出目前排列。

解題方法

在每一層,位置 ii 可以選用的元素,正是目前仍位於 list[i]list[i] 到 list[n]list[n] 的元素,因此迴圈範圍為 j=ij=i 到 nn,包含兩端。

每次選定 list[j]list[j] 後,先與 list[i]list[i] 交換,讓選定的元素固定在目前位置;再呼叫 perm(list, i+1, n),處理下一個位置。遞迴完成後,執行相同的交換以還原陣列。

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊
📄 以下 2 題共用同一段題幹

Consider the problem of finding a minimum spanning tree (MST): Given a weighted undirected graph, find a spanning tree with the best (minimum) cost, where the cost of a spanning tree is the sum of the weights of its edges.

第 3-(a) 題15 分

Describe an efficient algorithm for solving this problem. You should also analyze the time complexity of this algorithm and describe the data structure used by the algorithm.

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

最小生成樹(MST)是連通、無向、加權圖 G=(V,E)G=(V,E) 的一棵生成樹,使所有邊的權重總和最小。生成樹包含全部 ∣V∣|V| 個頂點,且恰有 ∣V∣−1|V|-1 條邊。

本題可使用 Kruskal 演算法。若目前選入的邊形成數個連通分量,將不同分量之間權重最小的邊加入,仍能保留取得 MST 的可能性。若某條邊的兩端已在同一分量,加入後會形成環,因此必須略過。

解題方法:Kruskal 演算法

先將所有邊依權重由小到大排序,再依序檢查。只有當一條邊連接兩個不同的連通分量時,才將它加入 MST。選入 ∣V∣−1|V|-1 條邊後,演算法完成。

Kruskal(G):
    將所有邊依權重由小到大排序
    對每個頂點建立一個獨立集合
    T = 空集合

    對排序後的每條邊 (u, v, w):
        若 Find(u) != Find(v):
            將 (u, v, w) 加入 T
            Union(u, v)
            若 |T| = |V| - 1:
                停止

    回傳 T

Find(x) 用來判斷頂點 xx 所屬的連通分量;Union(u,v) 將兩個分量合併。

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 3-(b) 題10 分

Now assume that we also want to know a spanning tree with the second best cost (if there is any which may be same as the best cost). For example, consider the graph with vertex set {1,2,3}\{1,2,3\} and edge set {(1,2,1),(1,3,1),(2,3,1)}\{(1,2,1),(1,3,1),(2,3,1)\}, where each triple (x,y,w)(x,y,w) represents that there is an edge with end vertices x,yx,y, and weight ww. Then the best and second best costs of spanning trees of this graph are both 2.

For another graph with the same vertex set and edge set {(1,2,1),(1,3,2),(2,3,3)}\{(1,2,1),(1,3,2),(2,3,3)\}, the best and second best costs of spanning trees of this graph are 3 and 4, respectively.

Design an algorithm to solve this problem.

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

生成樹是連通圖中包含所有頂點的無環子圖。題目所說的「第二佳成本」是把所有生成樹的成本由小到大排列後,第二個成本;因此若有不同生成樹同為最小成本,第二佳成本也可以等於最小成本。

用到的關鍵性質是生成樹的換邊性質:在一棵生成樹中加入一條原本不在樹上的邊,會形成唯一的環。從這個環移除一條邊,就會得到另一棵生成樹。

解題方法

先用 Kruskal 或 Prim 找出一棵最小生成樹 TT,其成本記為 WW。對每一條不在 TT 中的邊 e=(u,v)e=(u,v):

  1. 加入 ee,形成環;這個環由 ee 和 TT 中 uu 到 vv 的唯一路徑組成。
  2. 找出該路徑上權重最大的邊 ff。
  3. 移除 ff,得到另一棵生成樹,其成本為 W+w(e)−w(f).W+w(e)-w(f).
  4. 將所有這類成本取最小值,便是第二佳成本。

選擇路徑上的最大權重邊,是因為固定加入 ee 時,移除越重的邊,新生成樹的成本越低。若 w(e)=w(f)w(e)=w(f),換邊後成本仍為 WW,但生成樹已不同,正好能處理多棵最小生成樹的情況。

偽程式碼:

T = 用 Kruskal 找一棵最小生成樹
W = T 的總權重
bestSecond = +∞

對每條不在 T 中的邊 e = (u, v, weight):
    pathMax = T 中 u 到 v 路徑上的最大邊權
    candidate = W + weight - pathMax
    bestSecond = min(bestSecond, candidate)

若 bestSecond = +∞:
    不存在第二棵生成樹
否則:
    回傳 bestSecond
🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊
📄 以下 3 題共用同一段題幹

Given a set SS of nn real numbers, and another real number MM, we want to determine whether or not there exist 3 numbers in SS whose sum is exactly MM. The algorithm of testing all possible 3 numbers in SS will take O(n3)O(n^3) time and it is unacceptable.

Consider the following similar problem: Given a set SS of nn real numbers, another real number MM, and an integer kk, we want to determine whether or not there exist kk numbers in SS whose sum is exactly MM.

第 4-(a) 題10 分

Design a more efficient algorithm to solve the problem of determining whether there exist 3 numbers in SS whose sum is exactly MM. Analyze the time complexity of your algorithm.

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查排序後的雙指標法(two-pointer)。排序能讓指標移動方向具有明確規則:固定一個數後,若三數總和太小,就增加左側數值;若總和太大,就減少右側數值。

解題方法

先將 SS 由小到大排序。依序固定第 ii 個數 S[i]S[i],接著令左指標 j=i+1j=i+1、右指標 r=n−1r=n-1,檢查 S[i]+S[j]+S[r]S[i]+S[j]+S[r]:

  • 若總和等於 MM,表示找到三個數。
  • 若總和小於 MM,將 jj 右移。因為固定 i,ri,r 時,右指標左側的數不會更大,增加左指標數值才可能讓總和變大。
  • 若總和大於 MM,將 rr 左移。因為固定 i,ji,j 時,左指標右側的數不會更小,減少右指標數值才可能讓總和變小。

每次移動一個指標,都會排除目前不可能成功的組合。固定 ii 時,兩個指標最多各移動 nn 次,因此掃描時間為 O(n)O(n)。

關鍵程式碼

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 4-(b) 題5 分

Show that the problem of determining whether there exist kk numbers in SS whose sum is exactly MM is NP-complete.

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

要證明一個決定問題是 NP-complete(NP 完全),需完成兩件事:

  1. 屬於 NP:若答案為「是」,存在一份可在多項式時間內驗證的證明。
  2. NP-hard(NP 困難):從已知的 NP 完全問題,能在多項式時間內歸約到此問題。

題目以「實數」描述輸入;計算複雜度分析須假設數值有有限的位元表示。以下採用標準模型:輸入為二進位編碼的整數或有理數,且 kk 是輸入的一部分。

解題方法

一、證明問題屬於 NP

若答案為「是」,證明可以列出 SS 中被選出的 kk 個元素。驗證者檢查:

  • 所列元素確實屬於 SS,且沒有重複使用同一元素;
  • 這些元素的和等於 MM。

整數的加法與比較可在輸入位元長度的多項式時間內完成;有理數也可用精確運算驗證。因此,此問題屬於 NP。若 k>∣S∣k>|S|,答案直接為「否」。

二、從 Subset Sum 歸約

使用已知的 NP 完全問題 Subset Sum:給定正整數 a1,…,ana_1,\ldots,a_n 與目標值 TT,判斷是否存在一個索引子集 II,使得

∑i∈Iai=T.\sum_{i\in I}a_i=T.

將它轉換成題目的問題。令

A=3n.A=3^n.

對每個 i=0,1,…,n−1i=0,1,\ldots,n-1,在新集合中放入兩個數:

xi=Aai+1+3i,yi=3i.x_i=Aa_{i+1}+3^i,\qquad y_i=3^i.

設定新問題的參數為

k′=n,M′=AT+∑i=0n−13i.k'=n,\qquad M'=AT+\sum_{i=0}^{n-1}3^i.

直觀上,xix_i 代表選入 ai+1a_{i+1},yiy_i 代表不選;以 3i3^i 作為第 ii 個位置的標記,讓目標和強制每一對恰選一個數。

三、證明轉換正確

若 Subset Sum 有解 II,對每個 ii:

  • 若 i+1∈Ii+1\in I,選 xix_i;
  • 若 i+1∉Ii+1\notin I,選 yiy_i。

恰好選出 nn 個數,其總和為

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 4-(c) 題10 分

If MM is small enough, then it is possible to solve the above problem efficiently in O(nkM)O(nkM) time. Design such an algorithm.

登入後即可作答並保存紀錄。

這一題的完整詳解

題目條件的補充

O(nkM)O(nkM) 這個時間界是偽多項式(pseudo-polynomial)的:表格大小與 MM 的數值成正比,所以必須能把「目前的和」當成陣列索引 0,1,…,M0,1,\dots,M。題目說「MM 夠小時可以做到」,指的就是這種情況——SS 中的數都是非負整數(或是可以統一乘上同一個倍數化成非負整數,例如都只有固定位數的小數)。若 SS 含任意實數或負數,和的可能值無法用 0∼M0\sim M 的索引涵蓋,這個方法就不適用。以下在此前提下設計演算法。

核心觀念

這是 0/1 背包(subset sum)的變形:除了「和是多少」,還要追蹤「用了幾個數」。用動態規劃把狀態定為(考慮到第幾個數、已選幾個、目前和),每個數只有「選」或「不選」兩種轉移。

解題方法

令 S={s1,…,sn}S=\{s_1,\dots,s_n\},定義布林陣列

D[j][t]=是否能從已處理過的數中選出恰好 j 個,使總和恰為 t,0≤j≤k, 0≤t≤M.D[j][t]=\text{是否能從已處理過的數中選出恰好 } j \text{ 個,使總和恰為 } t,\quad 0\le j\le k,\ 0\le t\le M .
  1. 初始化:D[0][0]=trueD[0][0]=\text{true},其餘為 false。
  2. 依序處理每個數 sis_i(i=1…ni=1\ldots n)。為了讓每個數最多用一次,jj 由大到小、tt 由大到小更新:
D[j][t]←D[j][t] ∨ (t≥si ∧ D[j−1][t−si]),j=k,…,1,  t=M,…,si.D[j][t] \leftarrow D[j][t]\ \lor\ \big(t\ge s_i \ \land\ D[j-1][t-s_i]\big),\qquad j=k,\dots,1,\ \ t=M,\dots,s_i .

(大於 MM 的數不可能被選,直接略過;這一步正需要「數為非負」的前提。)
3. 全部處理完後,答案為 D[k][M]D[k][M]。

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

其他考古題