跳到主要内容

東京大学 情報理工学系研究科 コンピュータ科学専攻 2022年8月実施 専門科目 問題2

Author

zephyr

Description

We consider a division of a set of mutually distinct nn positive integers P={x1,x2,,xn}P = \{x_1, x_2, \ldots, x_n\} into mm sets P1,P2,,PmP_1, P_2, \ldots, P_m (1<m<n,P=P1P2Pm,i,j(ij)PiPj=)(1 < m < n, P = P_1 \cup P_2 \cup \ldots \cup P_m, \forall i, j (i \neq j) P_i \cap P_j = \emptyset), where \emptyset denotes an empty set. The set sequence Q=[P1,P2,,Pm]Q = [P_1, P_2, \ldots, P_m] is called a division of PP. We denote by S\|\mathbf{S}\| the summation of all the integers in SS if SS is a set of integers or a stack consisting of integers. Note that S=0\|\mathbf{S}\| = 0 in case SS is an empty set or an empty stack.

Let maxsum(Q)=maxiPi\mathrm{maxsum}(Q) = \max_i \|\mathbf{P}_i\| for a division Q=[P1,P2,,Pm]Q = [P_1, P_2, \ldots, P_m] of PP. Let minmaxsum(P,m)\mathrm{minmaxsum}(P, m) denote the minimum value of maxsum(Q)\mathrm{maxsum}(Q) among all the possible divisions QQ of PP into mm sets.

The following pseudo code shows an algorithm that computes an approximation of minmaxsum(P,m)\mathrm{minmaxsum}(P, m). Below, push(S,x)\mathrm{push}(S, x) pushes xx onto the stack SS, pop(S)\mathrm{pop}(S) pops the top element of the stack SS and returns the popped element, and top(S)\mathrm{top}(S) returns the top element of the stack SS. Note that top(S)\mathrm{top}(S) and pop(S)\mathrm{pop}(S) return the same value for the same stack SS, but top(S)\mathrm{top}(S) does not modify the stack.

approx-minmaxsum(integer set P,integer m)1:Q=[P1,P2,,Pm]An arbitrary division of P into m sets;2:for (1im)3:Sian empty stack;4:foreach (xPi) push(Si,x);5:while(1)6:jargmaxiSi;/* jone of the i’s that maximize Si */;7:kargminiSi;/* kone of the i’s that minimize Si */;8:if (top(Sj)+SkSj) break;9:push(Sk,pop(Sj));10:return Sj;\begin{array}{l} \textbf{approx-minmaxsum}(\text{integer set } P, \text{integer } m) \\ 1: \quad Q = [P_1, P_2, \ldots, P_m] \leftarrow \text{An arbitrary division of } P \text{ into } m \text{ sets}; \\ 2: \quad \textbf{for } (1 \leq i \leq m) \\ 3: \quad \quad S_i \leftarrow \text{an empty stack}; \\ 4: \quad \quad \textbf{foreach } (x \in P_i) \text{ push}(S_i, x); \\ 5: \quad \textbf{while}(1) \\ 6: \quad \quad j \leftarrow \arg\max_i \|\mathbf{S}_i\|; \quad \text{/* } j \leftarrow \text{one of the } i \text{'s that maximize } \|\mathbf{S}_i\| \text{ */}; \\ 7: \quad \quad k \leftarrow \arg\min_i \|\mathbf{S}_i\|; \quad \text{/* } k \leftarrow \text{one of the } i \text{'s that minimize } \|\mathbf{S}_i\| \text{ */}; \\ 8: \quad \quad \textbf{if } (\text{top}(S_j) + \|\mathbf{S}_k\| \geq \|\mathbf{S}_j\|) \textbf{ break}; \\ 9: \quad \quad \text{push}(S_k, \text{pop}(S_j)); \\ 10: \quad \textbf{return } \|\mathbf{S}_j\|; \end{array}

Answer the following questions.

(1) Calculate minmaxsum({3,4,5,6},2)\mathrm{minmaxsum}(\{3, 4, 5, 6\}, 2).

(2) Show minmaxsum(P,m)P/m\mathrm{minmaxsum}(P, m) \geq \|\mathbf{P}\| / m.

(3) Show that approx-minmaxsum(P,m)2minmaxsum(P,m)\mathrm{approx\text{-}minmaxsum}(P, m) \leq 2 \cdot \mathrm{minmaxsum}(P, m) holds, regardless of whatever division QQ is chosen in line 2 of the above code.

(4) Show that the while loop in the above code will be repeated at most nn times, regardless of whatever division QQ is chosen in line 2.

(5) Describe data structures needed to make the above algorithm run in O(nlogm)O(n \log m) time, and explain how to use them.


以下是中文翻译:

我们考虑将一组相互不同的 nn 个正整数 P={x1,x2,,xn}P = \{x_1, x_2, \ldots, x_n\} 划分为 mm 个集合 P1,P2,,PmP_1, P_2, \ldots, P_m (1<m<n,P=P1P2Pm,i,j(ij)PiPj=)(1 < m < n, P = P_1 \cup P_2 \cup \ldots \cup P_m, \forall i, j (i \neq j) P_i \cap P_j = \emptyset),其中 \emptyset 表示空集。集合序列 Q=[P1,P2,,Pm]Q = [P_1, P_2, \ldots, P_m] 称为 PP 的划分。我们用 S\|\mathbf{S}\| 表示 SS 中所有整数的和,如果 SS 是一个整数集合或由整数组成的堆栈。注意,若 SS 是空集合或空堆栈,则 S=0\|\mathbf{S}\| = 0

maxsum(Q)=maxiPi\mathrm{maxsum}(Q) = \max_i \|\mathbf{P}_i\|PP 的划分 Q=[P1,P2,,Pm]Q = [P_1, P_2, \ldots, P_m]。设 minmaxsum(P,m)\mathrm{minmaxsum}(P, m) 为在 PP 所有可能划分 QQmaxsum(Q)\mathrm{maxsum}(Q) 的最小值。

下面的伪代码展示了一种计算 minmaxsum(P,m)\mathrm{minmaxsum}(P, m) 近似值的算法。下面,push(S,x)\mathrm{push}(S, x)xx 压入堆栈 SSpop(S)\mathrm{pop}(S) 弹出堆栈 SS 的顶部元素并返回弹出的元素,而 top(S)\mathrm{top}(S) 返回堆栈 SS 的顶部元素。注意,top(S)\mathrm{top}(S)pop(S)\mathrm{pop}(S) 为相同堆栈 SS 返回相同的值,但 top(S)\mathrm{top}(S) 不会修改堆栈。

approx-minmaxsum(integer set P,integer m)1:Q=[P1,P2,,Pm]An arbitrary division of P into m sets;2:for (1im)3:Sian empty stack;4:foreach (xPi) push(Si,x);5:while(1)6:jargmaxiSi;/* jone of the i’s that maximize Si */;7:kargminiSi;/* kone of the i’s that minimize Si */;8:if (top(Sj)+SkSj) break;9:push(Sk,pop(Sj));10:return Sj;\begin{array}{l} \textbf{approx-minmaxsum}(\text{integer set } P, \text{integer } m) \\ 1: \quad Q = [P_1, P_2, \ldots, P_m] \leftarrow \text{An arbitrary division of } P \text{ into } m \text{ sets}; \\ 2: \quad \textbf{for } (1 \leq i \leq m) \\ 3: \quad \quad S_i \leftarrow \text{an empty stack}; \\ 4: \quad \quad \textbf{foreach } (x \in P_i) \text{ push}(S_i, x); \\ 5: \quad \textbf{while}(1) \\ 6: \quad \quad j \leftarrow \arg\max_i \|\mathbf{S}_i\|; \quad \text{/* } j \leftarrow \text{one of the } i \text{'s that maximize } \|\mathbf{S}_i\| \text{ */}; \\ 7: \quad \quad k \leftarrow \arg\min_i \|\mathbf{S}_i\|; \quad \text{/* } k \leftarrow \text{one of the } i \text{'s that minimize } \|\mathbf{S}_i\| \text{ */}; \\ 8: \quad \quad \textbf{if } (\text{top}(S_j) + \|\mathbf{S}_k\| \geq \|\mathbf{S}_j\|) \textbf{ break}; \\ 9: \quad \quad \text{push}(S_k, \text{pop}(S_j)); \\ 10: \quad \textbf{return } \|\mathbf{S}_j\|; \end{array}

回答以下问题。

(1) 计算 minmaxsum({3,4,5,6},2)\mathrm{minmaxsum}(\{3, 4, 5, 6\}, 2)

(2) 证明 minmaxsum(P,m)P/m\mathrm{minmaxsum}(P, m) \geq \|\mathbf{P}\| / m

(3) 证明不论第 2 行选择何种划分 QQapprox-minmaxsum(P,m)2minmaxsum(P,m)\mathrm{approx\text{-}minmaxsum}(P, m) \leq 2 \cdot \mathrm{minmaxsum}(P, m)

(4) 证明不论第 2 行选择何种划分 QQ,上述代码中的 while 循环最多重复 nn 次。

(5) 描述所需的数据结构以使上述算法运行在 O(nlogm)O(n \log m) 时间内,并解释如何使用它们。

题目描述

将由 nn 个互异正整数构成的集合 P={x1,,xn}P=\{x_1,\ldots,x_n\} 划分为 mm 个两两不交、并集为 PP 的集合 P1,,PmP_1,\ldots,P_m,其中 1<m<n1<m<n;记划分为 Q=[P1,,Pm]Q=[P_1,\ldots,P_m]。对整数集合或整数栈 SS,以 S\|S\| 表示元素总和,空集合或空栈的和为 00。定义

maxsum(Q)=maxiPi,\operatorname{maxsum}(Q)=\max_i\|P_i\|,

并以 minmaxsum(P,m)\operatorname{minmaxsum}(P,m) 表示所有 mm 划分中上述最大和的最小值。

题中近似算法从任意划分开始,把每个 PiP_i 的元素压入栈 SiS_i;循环选择总和最大的栈 SjS_j 和总和最小的栈 SkS_k。若

top(Sj)+SkSj,\operatorname{top}(S_j)+\|S_k\|\ge\|S_j\|,

则停止并返回 Sj\|S_j\|;否则将 SjS_j 的栈顶弹出并压入 SkS_k。回答下列问题。

(1)计算 minmaxsum({3,4,5,6},2)\operatorname{minmaxsum}(\{3,4,5,6\},2)

(2)证明

minmaxsum(P,m)Pm.\operatorname{minmaxsum}(P,m)\ge\frac{\|P\|}{m}.

(3)证明无论初始任意划分如何选择,算法返回值均满足

approx-minmaxsum(P,m)2minmaxsum(P,m).\operatorname{approx\text{-}minmaxsum}(P,m) \le2\,\operatorname{minmaxsum}(P,m).

(4)证明无论初始划分如何选择,while 循环最多重复 nn 次。

(5)说明使算法达到 O(nlogm)O(n\log m) 运行时间所需的数据结构及其用法。

考点

  • 最小化最大分组和:以平均负载作为最优值下界,理解 minimax 划分目标。
  • 二近似证明:利用终止条件、最大单元素与平均负载界住算法结果。
  • 势函数与终止性:证明每次迁移具有单调进展,从而限制循环次数。
  • 优先队列:分别维护当前总和的最大、最小栈,并支持对两个键的对数时间更新。

Kai

(1)

To find minmaxsum({3,4,5,6},2)\mathrm{minmaxsum}(\{3, 4, 5, 6\}, 2), we need to find the optimal way to divide the set {3,4,5,6}\{3, 4, 5, 6\} into two subsets such that the maximum subset sum is minimized.

The total sum of the set PP is:

P=3+4+5+6=18\|\mathbf{P}\| = 3 + 4 + 5 + 6 = 18

We need to divide this into two subsets such that the maximum sum is as small as possible. We can consider the following possible divisions:

  • P1={3,6},P2={4,5}P_1 = \{3, 6\}, P_2 = \{4, 5\}:

    • P1=3+6=9\|\mathbf{P}_1\| = 3 + 6 = 9
    • P2=4+5=9\|\mathbf{P}_2\| = 4 + 5 = 9
    • Maximum sum = 9
  • P1={3,5},P2={4,6}P_1 = \{3, 5\}, P_2 = \{4, 6\}:

    • P1=3+5=8\|\mathbf{P}_1\| = 3 + 5 = 8
    • P2=4+6=10\|\mathbf{P}_2\| = 4 + 6 = 10
    • Maximum sum = 10
  • P1={3,4},P2={5,6}P_1 = \{3, 4\}, P_2 = \{5, 6\}:

    • P1=3+4=7\|\mathbf{P}_1\| = 3 + 4 = 7
    • P2=5+6=11\|\mathbf{P}_2\| = 5 + 6 = 11
    • Maximum sum = 11

The minimum maximum sum among these divisions is 9. Therefore:

minmaxsum({3,4,5,6},2)=9\mathrm{minmaxsum}(\{3, 4, 5, 6\}, 2) = 9

(2)

Let P={x1,x2,,xn}P = \{x_1, x_2, \dots, x_n\}, and suppose we divide PP into mm subsets P1,P2,,PmP_1, P_2, \dots, P_m. By definition:

minmaxsum(P,m)=minQmaxiPi\mathrm{minmaxsum}(P, m) = \min_Q \max_i \|\mathbf{P}_i\|

where QQ is a possible division of PP into mm subsets.

For any division QQ, the sum of all elements in PP must equal the sum of the elements in all subsets:

i=1mPi=P\sum_{i=1}^m \|\mathbf{P}_i\| = \|\mathbf{P}\|

Let M=maxiPiM = \max_i \|\mathbf{P}_i\|. Then:

mMPm \cdot M \geq \|\mathbf{P}\|

because the total sum is distributed across mm subsets, and the largest subset sum must be at least P/m\|\mathbf{P}\| / m:

MPmM \geq \frac{\|\mathbf{P}\|}{m}

Since minmaxsum(P,m)\mathrm{minmaxsum}(P, m) is the minimum possible value of MM, we have:

minmaxsum(P,m)Pm\mathrm{minmaxsum}(P, m) \geq \frac{\|\mathbf{P}\|}{m}

(3)

The algorithm attempts to balance the largest and smallest subset sums by moving the top element from the stack with the largest sum to the stack with the smallest sum until no improvement can be made.

Let M=minmaxsum(P,m)M = \mathrm{minmaxsum}(P, m). Initially, each subset in the division QQ has a sum less than or equal to MM.

When the algorithm moves an element from the subset with the largest sum to the subset with the smallest sum, the maximum possible increase in the smallest sum is bounded by the value of the largest element moved. This adjustment ensures that the final maximum sum MfM_f in the approximate solution satisfies:

MfM+M2MM_f \leq M + M \leq 2M

Thus:

approx-minmaxsum(P,m)2minmaxsum(P,m)\mathrm{approx\text{-}minmaxsum}(P, m) \leq 2 \cdot \mathrm{minmaxsum}(P, m)

(4)

Each iteration of the while loop in the pseudo-code moves an element from the stack SjS_j (which has the maximum sum) to the stack SkS_k (which has the minimum sum). Since the total number of elements in all stacks is nn, and each move reduces the number of elements in SjS_j by one, the maximum number of iterations cannot exceed nn. After nn moves, the stacks have been exhausted of elements that can be moved:

Number of while loop iterations n\text{Number of while loop iterations } \leq n

(5)

To achieve an O(nlogm)O(n \log m) runtime, we can use a priority queue (or a binary heap) for efficiently finding and updating the stacks with the maximum and minimum sums. The steps are as follows:

  1. Initialize: Use two priority queues, one for the stack with the maximum sum and one for the stack with the minimum sum.

    • Insert each stack's sum along with its identifier into the respective priority queues. Both insertion and deletion in a priority queue take O(logm)O(\log m) time.
  2. Update: During each iteration of the while loop:

    • Extract the maximum from the "max" priority queue and the minimum from the "min" priority queue.
    • Perform the pop operation from the stack with the maximum sum and push the element onto the stack with the minimum sum.
    • Update the priority queues with the new sums. This step also takes O(logm)O(\log m) time.

Since each operation inside the while loop is O(logm)O(\log m), and the loop runs at most nn times, the total time complexity of the algorithm is O(nlogm)O(n \log m).

Knowledge

贪心算法 集合划分 复杂度分析

重点词汇

  • division: 划分
  • priority queue: 优先队列
  • minmax: 最小最大化

参考资料

  1. Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to Algorithms (3rd ed.). MIT Press. Chapter 16: Greedy Algorithms.
  2. Kleinberg, J., & Tardos, É. (2005). Algorithm Design. Pearson. Chapter 6: Greedy Algorithms.