算法导论 34 Problems 答案

34-1

a

G=(V,E) 的一个独立集 V 意味着以节点集合 V 的子图不包含任何一条边。

这个判定性问题是:对于图 G=(V,E),是否存在一个大小至少为 k 的点集 VV,使得 (u,v)E,¬(uVvV) 均成立。

将这个问题定义成一种语言 INDEPENDENT-SET

INDEPENDENT-SET={G,k:G=(V,E) is anundirected graph, k0 is an integer, andG contains a independent set at least k vertex}

首先证明 INDEPENDENT-SET 属于 NP。对于一个集合 V,检验程序只需要对 E 中的所有边 (u,v) 进行判断是否 u,v 都在 V 中,以及判断是否满足 |V|k 即可。检验程序可以在多项式时间内运行,因此 INDEPENDENT-SET 属于 NP

接下来证明 INDEPENDENT-SET 是 NP 困难的,考虑使用团问题进行规约,即证明 CLIQUEPINDEPENDENT-SET。对于 CLIQUE 问题中的任意一个实例 G,k,规约算法 F 构造出如下一个 INDEPENDENT-SET 问题的实例 G,k,使得 G=(V,E) 包含一个大小为 k 的团,当且仅当 G=(V,E) 包含一个大小为 k 的独立集。

规约过程是:令 V=V,E=E,即 G G 的补图,且 k=k。可见,G 的补图可以在多项式时间内被求出来,因此规约算法 F 是多项式时间的。

现在证明 G=(V,E) 包含一个大小为 k 的团,当且仅当 G=(V,E) 包含一个大小为 k 的独立集。

充分性:如果 G 中存在一个大小为 k 的团 V1,那么在 G 的补图 G 中,节点集合 V1 中的任意两点都没有 E 中的边,因此 V1 也是 G 中的一个独立集。

必要性:如果 G 中存在一个大小为 k 的独立集 V1,那么在 G 的补图 G 中,节点集合 V1 中的任意两点都有 E 中的边相连,因此 V1 也是 G 中的一个团。

因此 CLIQUEPINDEPENDENT-SET。由于 CLIQUE 是 NP 完全的,那么 INDEPENDENT-SET 是 NP 困难的,也是 NP 完全的,原结论成立。

b

首先可以使用二分法,用于确定最大独立集的大小 k,这仅需要 O(lgV) 次使用 INDEPENDENT-SET。接下来,由于移除一个顶点并不会以及其关联的所有边增大,因此考虑尝试移除每一个顶点,并使用 INDEPENDENT-SET 判断图中是否仍然有一个至少为 k 的独立集,如果仍然有,说明这个顶点不是必要的,可以删除。否则必须保留下来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MAX-INDEPENDENT-SET(G)
l = 1
r = |G.V|
while l < r
mid = ⌊(l + r + 1) / 2⌋
if INDEPENDENT-SET(G, mid) == 1
l = mid
else
r = mid - 1
k = l
VI = ∅
V = G.V
E = G.V
while V != ∅
select v from V randomly
V = V - {v}
E' = E - {(w, v) : (w, v) ∈ E and w ∈ V}
if INDEPENDENT-SET((V ∪ VI, E'), mid) == 1
E = E'
else
VI = VI ∪ {v}
return VI

c

如果图 G=(V,E) 的每个节点度数为 2,那么这意味着 G 是由多个不相交的环 C 构成。遍历每个环 C,那么这个环中不相邻的所有节点就是一个独立集(这保证了这些节点之间将不会有边进行连接,因此这是一个独立集,且是一个极大的独立集)。最终,所有环中的极大独立集拼起来,就是图 G=(V,E) 的最大独立集。具体过程由 MAX-INDEPENDENT-SET-DEGREE-2 给出,其时间复杂度为 O(V+E)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MAX-INDEPENDENT-SET-DEGREE-2(G)
let vis[1 : |G.V|] be a new array by False
S = ∅
for each vertex u in G.V
if vis[u] == false
T = ∅
cnt = 0
while True
if cnt % 2 == 1
T = T ∪ {u}
vis[u] = True
cnt = cnt + 1
// 表示u的两个相邻节点
v = G.Adj[u, 0]
w = G.Adj[u, 1]
if vis[v] == False
u = v
else if vis[w] == False
u = w
else
break
S = S ∪ T
return S

d

首先考虑图 G=(V,E) 最大独立集问题和最小点覆盖问题的可规约性:对于一个点覆盖 V,在图 G=(V,E) 中,将 V V 关联的所有边删去后,剩下的图不会含有任何一条边,因此 VV G 的一个独立集。因此对于 G 的一个最小点覆盖 V0,那么得知 VV0 就是图 G 的一个最大独立集。

接下来考虑二分图 G 下最小点覆盖问题和最大匹配的问题的等价性。

首先说明图 G=(V,E),V=LR 的最小点覆盖中的点数不可能小于最大匹配的边数,因为最大匹配是由多条不相交的边构成的,这些边都至少需要一个顶点进行覆盖。接下里证明图 G 最小点覆盖中的点数恰好为最大匹配的边数。

考虑如下一个构造方法,最终通过二分图最大匹配算法得到二分图的最小点覆盖:

  1. 求出 G 的最大匹配。
  2. 再次从 L 中所有节点非匹配节点出发,寻找一条增广路径(且一定寻找失败)。
  3. L 中尚未被标记的节点 L0R 中被标记过的节点 R0,这些顶点构成了 G 的一个最小点覆盖 V0=L0R0

接下来证明这个方法构造出来的 V0 是一个最小点覆盖。运行完整个增广路径算法后,对于 L 中的非匹配节点,它们一定都被标记,因为它们是出发点;而对于 R 中非匹配节点,它们一定都没有被标记,否则就找到了一条增广路径。对于一条匹配边,两边的节点要么被标记,要么没有被标记,因为左部节点只能通过匹配边从右部节点进行访问。

可以发现,L0 R0 恰好是从最大匹配中,来自每条边的两个节点之一。L0 中节点所对应的匹配边,是指增广路径算法中没有访问的边;R0 中节点所对应的匹配边,是指增广路径算法中有访问的边。接下来验证这个点覆盖确实覆盖了所有边:

  1. 左部节点 lL 是非匹配点,右部节点 rR 也是非匹配点。这种边是不可能存在的,因为这是一条增广路径。
  2. l 是匹配点,r 也是匹配点。这种边被覆盖了,因为每条匹配边的其中一个节点都在 V0 中。
  3. l 是匹配点,r 是非匹配点。这说明 l 没有被访问到,否则找到了通向 r 的增广路径,因此这条边是被 L0 中的节点覆盖。
  4. l 是非匹配点,r 是匹配点。因为起点是 l,所以 r 一定被访问,因此这条边是被 R0 中的节点覆盖。

自此证明了最大匹配问题和最小点覆盖问题的等价性。可以给出如下过程 MAX-INDEPENDENT-SET-BIPARTITE,其时间复杂度取决于增广路径算法的时间复杂度,因此这个算法是多项式时间的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MAX-INDEPENDENT-SET-BIPARTITE(G)
M = HOPCROFT-KARP(G)
// 记录被标记的节点
construct GM from M and G
Q = Ø
L0 = Ø
R0 = Ø
for each unmatched vertex l ∈ L
l.π = NIL
ENQUEUE(Q, l)
L0 = L0 ∪ {l}
while Q != Ø
u = DEQUEUE(Q)
for each v in GM.Adj[u]
if v in L and v not in L0
L0 = L0 ∪ {v}
ENQUEUE(Q, v)
else if v in R and v not in R0
R0 = R0 ∪ {v}
ENQUEUE(Q, v)
V0 = (L - L0) ∪ R0
return V - V0

34-2

a

这是一个多项式时间的算法即可完成。

当钱的总数为奇数时,必定无法分成。

假设有 a x 美元的硬币,na y 美元的硬币,那么这些钱的总共的价值为 ax+(na)y,那么每一个人将分得 s=ax+(na)y2 块钱。

接下来使用扩展欧几里得算法对关于 (u,v) 的方程 xu+yu=s 进行求解,并尝试找到一个满足 0ua,0vna 的整数解,这将在多项式的时间内完成。更具体的过程由 DIVIDING-MONEY-A 给出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
DIVIDING-MONEY-A(a, n, x, y)
b = n - a
s = (a * x + b * y)
if s % 2 != 0
return 0
s = s / 2
(d, u, v) = EXTENDED-EUCLID(x, y)
if s % d != 0
return 0
u0 = (u * (s / d)) % y
// 求取使u满足u<=a的最大解。
u1 = u0 + ⌊(a - u0) / (y / d)⌋ * (y / d)
v1 = (s - u1 * x) / y
if 0 <= u1 <= a and 0 <= v1 <= b
return 1
v0 = (v * (s / d)) % x
// 求取使v满足v<=b的最大解。
v2 = v0 + ⌊(b - v0) / (x / d)⌋ * (x / d)
u2 = (s - v2 * y) / x
if 0 <= u2 <= a and 0 <= v2 <= b
return 1
return 0

b

这是一个多项式时间的算法即可完成。将所有币依照币值大小从大到小分配,每次分配给持有币值总数较小的那个人,更具体的过程由 DIVIDING-MONEY-B 给出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DIVIDING-MONEY-B(X, n)
Bonnie-s = 0
Clyde-s = 0
RANDOMIZED-QUICKSORT(X, 1, n)
for i = n downto 1
if Bonnie-s <= Clyde-s
Bonnie-s = Bonnie-s + X[i]
X[i] will be assigned to Bonnie
else
Clyde-s = Clyde-s + X[i]
X[i] will be assigned to Clyde
if Bonnie-s == Clyde-s
return 1
else
return 0

可见,这个算法是多项式的,接下来说明这个算法能够正确地运行。假设现在遍历到 xi,Bonnie 得到了 sB 美元,Clyde 得到了 sC 美元。如果当前 2 个人得到的钱相等,那么将 xi 可以随机分配给一个人,不失一般性,假设分配给了 Bonnie,因此在整个过程中,总有 sBsC。如果现在 sB>sC,由于 ji,xixj 均成立,因此总有 xisBsC,并假设分配 xi1 之前,有 sB=sC(这样的起点 i 必定存在,例如 i=2,在分配 x1 B 前有 sB=sC),那么接下来按顺序将所有钱都给 Clyde,直到 sB=sC 这个临界点,如果能够达到 sB=sC,那么以这个临界点为下一个起点。否则说明接下来剩下的钱都不足以弥补当前 sBsC 的差值。因此,DIVIDING-MONEY-B 是多项式时间内可行的算法。

c

这恰好是题目 34.5-5 所提到的集合划分问题 SET-PARTITION,它已经被证明是 NP 完全的。

d

这个问题是 NP 完全的,如下是证明。

先将这个问题定义成一种语言 SET-PARTITION-100

SET-PARTITION-100={S:there exists a set AS such that |xAxxAx|100}

首先证明 SET-PARTITION-100 属于 NP。对于 S 和它的一个非空子集 A,检验程序只需要判断 |xAxxAx|100 是否满足即可,它可以在多项式时间内运行,因此 SET-PARTITION-100 属于 NP

接下来证明 SET-PARTITION-100 是 NP 困难的,考虑使用集合划分问题进行规约,即证明 SET-PARTITIONPSET-PARTITION-100。对于 SET-PARTITION 问题中的任意一个实例 S,规约算法 F 构造出如下一个 SET-PARTITION-100 问题的实例 S,使得 S 能够划分成两个和值相等的子集,当且仅当 S 能够划分成两个和值相差不超过 100 的子集。

规约过程是:令 S={101xxS}。可见只是将集合 S 中的每个数乘上 101,再将它插入集合 S。可见这个过程是多项式可以完成的。

现在证明 S 能够划分成两个和值相等的子集,当且仅当 S 能够划分成两个和值相差不超过 100 的子集。

充分性:如果 S 能够划分成两个和值相等的集合 A,A,将 A,A 中的所有元素都乘上 101,得到 A,A。可见 A,A 也是 S 的一个划分,并且差值为 0101=0,因此 A,A S 一个满足条件的划分。

必要性:假设 S 包含两个和值相差不超过 100 的集合 A,A。由于 S 中所有数都是 101 的倍数,因此 A,A 的元素和也都是 101 的倍数,因此如果要满足假设,两个集合的元素和必须相等。因此,将 A,A 中的所有元素都除上 101,得到 A,A。可见 A,A S 一个满足条件的划分。

因此 SET-PARTITIONPSET-PARTITION-100。由于 SET-PARTITION 是 NP 完全的,那么 SET-PARTITION-100 是 NP 困难的,也是 NP 完全的,原结论成立。

34-3

a

题目 20.2-7 所给出的判断二分图的算法即为所求,其时间复杂度为 O(V+E)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DETERMINE-WRESTLERS(G)
for each vertex u in G.V
u.type = NIL
for each vertex s in G.V
if s.type == NIL
s.type = babyface
Q = ∅
ENQUEUE(Q, s)
while Q != ∅
u = DEQUEUE(Q)
for each vertex v in G.Adj[u]
if v.type == NIL
if u.type == babyface
v.type = heel
else
v.type = babyface
ENQUEUE(Q, s)
else if v.type == u.type
return NIL
return G.V

b

这个判定性问题是:对于图 G=(V,E),是否至多可以用 k 种颜色进行着色。假设判定性问题的语言定义为 K-COLOR

K-COLOR={G,k:G=(V,E) is anundirected graph, k1 is an integer, andthere exists a function c:V{1,2,,k} such that (u,v)E,c(u)c(v)}

接下来证明 K-COLOR 能够在多项式时间内能够解决,当且仅当图着色问题可以在多项式时间内解决。

必要性:显而易见,图着色问题如果能够在多项式算法内解决,那么 K-COLOR 只需要统计图着色问题求解中所使用的颜色个数 k,再判断是否不超过给定的 k 值即可。因此 K-COLOR 也可以在多项式时间内解决。

充分性:假设 K-COLOR 多项式时间内可解决。可见,只需要最多 |V| 种颜色,就可以将图 G 完成着色。因此图着色问题考虑使用 K-COLOR 作为子程序,依照二分法的思想,即可能够判断出对图 G 的着色最少颜色数,那么图着色问题至多只需要询问 O(lgV)K-COLOR。由于 K-COLOR 是多项式时间内可解决的,因此图着色问题也是多项式时间内可解决的。

因此原结论成立。

c

首先证明 K-COLOR 属于 NP。对于 G 和它的一个着色函数 c,检验程序只需要判断是否 (u,v)E,c(u)c(v) 均成立,并判断 c(u) 的取值是否在 [1,k] 中即可。它可以在多项式时间内运行,因此 K-COLOR 属于 NP

接下来证明 K-COLOR 是 NP 困难的,考虑使用三着色问题进行规约,即证明 3-COLORPK-COLOR。对于 3-COLOR 问题中的任意一个实例 G,规约算法 F 构造出如下一个 K-COLOR 问题的实例 G,k,使得图 G 3 着色的,当且仅当图 G k 着色的。

规约过程是:只需要令 k=3 即可。

现在证明图 G 3 着色的,当且仅当图 G k 着色的。当 k=3 时,这两个问题是两个完全相同的问题,因此充分性和必要性均成立。

因此 3-COLORPK-COLOR。由于题目已经假设了 3-COLOR 是 NP 完全的,因此 K-COLOR 是 NP 困难的,也是 NP 完全的,原结论成立。

d

在图 G=(V,E) 中,3 个特殊节点 RED,TRUE,FALSE 两两相连,因此 G 中的 3 中颜色只能用 c(RED),c(TRUE),c(FALSE) 分别表示。从图 34.20 中可以看出,i[1,n],节点 xi,¬xi,RED 3 个节点两两相连,因此 xi ¬xi 这两个节点只能其中一个着色为 c(TRUE),另一个为 c(FALSE)

对于每对节点 xi,¬xi,如果公式在公式 ϕ 中,最终 xi 赋值为 1,那么节点 xi 着色为 c(TRUE),¬xi 着色成 c(FALSE);如果 xi 赋值为 0,那么节点 xi 着色为 c(FALSE),¬xi 着色成 c(TRUE) 即可。

因此,对于 ϕ 中的任意一种赋值,都对应着只包含文字的图的其中一种 3 着色。

e

假设将每个组件中,先从左到右,再从上到下的 5 个节点分别命名为 a,b,c,d,e

那么考虑枚举节点 x,y,z,a,b,c,d,e 的着色情况,一共有 2335 种不同的情况。对每种情况进行判断,最终可以得到一个组件图中有如下 3 着色的方式,一共有 20 种:

xyzabcdec(TRUE)c(FALSE)c(FALSE)c(FALSE)c(RED)c(TRUE)c(FALSE)c(RED)c(TRUE)c(FALSE)c(FALSE)c(FALSE)c(TRUE)c(RED)c(FALSE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(TRUE)c(FALSE)c(RED)c(FALSE)c(RED)c(TRUE)c(TRUE)c(FALSE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(RED)c(TRUE)c(TRUE)c(FALSE)c(FALSE)c(RED)c(TRUE)c(FALSE)c(RED)c(FALSE)c(FALSE)c(TRUE)c(RED)c(TRUE)c(FALSE)c(RED)c(FALSE)c(FALSE)c(FALSE)c(TRUE)c(TRUE)c(RED)c(FALSE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(TRUE)c(RED)c(TRUE)c(FALSE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(TRUE)c(FALSE)c(RED)c(TRUE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(TRUE)c(FALSE)c(RED)c(TRUE)c(FALSE)c(RED)c(TRUE)c(FALSE)c(TRUE)c(FALSE)c(TRUE)c(RED)c(FALSE)c(RED)c(FALSE)c(TRUE)c(TRUE)c(TRUE)c(RED)c(FALSE)c(RED)c(FALSE)c(FALSE)c(TRUE)c(TRUE)c(RED)c(FALSE)c(TRUE)c(RED)c(FALSE)c(FALSE)c(TRUE)c(TRUE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(RED)c(FALSE)c(TRUE)c(TRUE)c(TRUE)c(FALSE)c(RED)c(FALSE)c(RED)c(TRUE)c(TRUE)c(TRUE)c(RED)c(FALSE)c(TRUE)c(RED)c(FALSE)c(TRUE)c(TRUE)c(TRUE)c(FALSE)c(RED)c(TRUE)c(RED)c(FALSE)c(TRUE)c(TRUE)c(TRUE)c(RED)c(FALSE)c(TRUE)c(FALSE)c(RED)c(TRUE)c(TRUE)c(TRUE)c(FALSE)c(RED)c(TRUE)c(FALSE)c(RED)

按照上面的表可以发现,这个组件图如果是 3 着色的,那么 x,y,z 必定有一个着色成 c(TRUE),原结论成立。

需要注意的是,只要 x,y,z 不同时被着色成 c(FALSE),那么另外 7 种组合着色情况都是有对应的 3 着色方案对应着。

f

首先证明 3-COLOR 属于 NP。这个证明过程和题目 34-3-c 相同,只需要取 k=3 即可。因此 3-COLOR 属于 NP

接下来证明 3-COLOR 是 NP 困难的,考虑使用 3-CNF 可满足性问题问题进行规约,即证明 3-CNF-SATP3-COLOR。对于 3-CNF-SAT 问题中的任意一个实例 ϕ,规约算法 F 构造出如下一个 3-COLOR 问题的实例 G,使得 3-CNF 布尔公式 ϕ 是可满足的,当且仅当图 G 3 着色的。

规约过程是:按照题目 34-3-c 和题目 34-3-d 之间的提示构造出了一个图 G=(V,E)V 一共有 2n+5m+3 个节点,其中包含了 2n 个文字节点,m 个组件中,每个组件有 5 个节点,以及 3 个特殊节点;E 一共有 3n+10m+3 条边,其中有 3n+3 条文字边,10m 条子句边。因此 G 可以在多项式时间内构造出来,故规约算法 F 是多项式时间的。

现在证明 3-CNF 布尔公式 ϕ 是可满足的,当且仅当图 G 3 着色的。

充分性:由于 ϕ 是可满足的,因此考虑其中一组可满足行赋值,并将 2n 个文字节点然上对应的颜色。这也意味着,对于所有子句 ϕi,每个子句至少有一个文字的值为 1。可以在表中选择对应的表项,将图 G 中对应的组件内部的 5 个节点染上表项对应颜色。因此,每个文字节点和组件内部的节点颜色都不会和相邻节点颜色相同,所求着色方式说明图 G 3 着色的。

必要性:由于图 G 3 着色的,因此存在一种 3 着色方案。对于图 G 的第 i 个组件,它的着色方式必定是 20 个表项之一,然而所有表项中,x,y,z 三个节点必定其中一个着色为 c(TRUE),因此 ϕi 对应文字也为 1,对于其它子句也是如此。此外,这个 3 着色方案中,如果 xi 被染成 c(TRUE),那么 xi 赋值为 1,否则赋值为 0。最终这个着色方案意味着这个 3-CNF 公式 ϕ 是可满足的。

因此 3-CNF-SATP3-COLOR。由于 3-CNF-SAT 是 NP 完全的,因此 3-COLOR 是 NP 困难的,也是 NP 完全的,原结论成立。

34-4

a

这个判定性问题是:是否存在一个 n 阶排列 σ,使得按照顺序 aσ(1),aσ(2),,aσ(n) 执行任务,可以获得至少 k 的利润。可以将这个判定问题定义成一种语言 K-PROFIT-DEADLINES

K-PROFIT-DEADLINES={A,k:A={a1,a2,,an} is a tasks set, k0 is an integer, andthere exists a sequence to finish thest task and get at leastprofit k}

b

首先证明 K-PROFIT-DEADLINES 属于 NP。给定一个任务清单 A 和整数 k,以及一个完成顺序 σ,检验程序需要模拟这些任务的完成时间,并且需要判断完成时间是否会超过截止时间,如果没有超过截止时间就算上利润 pi,最终判断获得的总利润 k 是否超过 k 即可。因此检验程序可以在多项式时间内完成模拟,因此 K-PROFIT-DEADLINES 属于 NP

接下来证明 K-PROFIT-DEADLINES 是 NP 困难的,考虑使用子集和问题问题进行规约,即证明 SUBSET-SUMPK-PROFIT-DEADLINES。对于 SUBSET-SUM 问题中的任意一个实例 S,t,规约算法 F 构造出如下一个 K-PROFIT-DEADLINES 问题的实例 A,k,使得 S 包含一个和为 t 的子集,当且仅当 A 中的任务按照某个顺序执行,能够获得至少 k 的利润。

规约过程是:对于集合 S 中的第 i 个数 xi,可以构造如下任务 ai:ti=xi,pi=ai,di=t。此外,至少得到利润 k=t。可见这个规约过程仅仅是将 S 中的每个数都建立了一个任务,并且添加了一个数 t 作为利润上限。这些内容可以在多项式时间内构造出来,因此规约算法 F 是多项式时间的。

现在证明 S 包含一个和为 t 的子集,当且仅当 A 中的任务按照某个顺序执行,能够获得至少 t 的利润。

充分性:如果 S 包含一个和为 t 的子集 S,那么只需要按任意顺序执行 S 在中 A 对应的任务(AA 的任务按随意顺序执行,反正得不到利润),就可以得到恰好 t 的利润,这个任务执行计划是满足要求的。

必要性:假设 A 中的任务按某种顺序执行可以得到至少 t 利润。由于 A 中所有任务的截止时间都相等(均为 t),因此在 t 时间前执行的任务并不需要固定的顺序。此外,由于每个任务单位时间内所获得的利润都是 1,因此在时间 t 内,恰好只能获得利润 t。也就是说,存在一个 A 子集 A,其利润之和恰好为 t。将集合 A 中的任务映射回 S 中的数,那么就得到了一个子集和为 t 的集合。

因此 SUBSET-SUMPK-PROFIT-DEADLINES。由于 SUBSET-SUM 是 NP 完全的,因此 K-PROFIT-DEADLINES 是 NP 困难的,也是 NP 完全的,原结论成立。

c

由于超过了任务期限后再完成任务,再也不能得到利润,因此我们可以先选择尽力完成一部分能够得到利润的任务,再完成剩下的另一部分任务。选定了一部分任务后,只有按照截止日期按顺序完成,才能够达到最大利润。因此需要对任务按照截止时间进行排序。

令状态 f[i,j](i,j0) 表示时间 j 内完成前 i 个任务所能获得最大的利润。那么不难写出关于 f[i,j] 的状态转移方程:

f[i,j]={0ifi=0f[i1,j]ifi>0(j<tij>di)max{f[i1,jti]+pi,f[i1,j]}ifi>0(tijjdi)

那么对于状态 f[i,j],要么不完成(或者无法完成)第 i 个任务,从 f[i1,j] 转移过来,要么尽力完成第 i 个任务,并获得 pi 的利润,从 f[i1,jti] 转移而来。

至此,f[n,T] 则是可以获得的最大利润,其中 T=i=1nti

由于此时仅要求给出的是一个判定性算法,因此只需要对至少获取的利润 k f[n,T] 进行比较即可。具体过程由程序 K-PROFIT-DEADLINES' 给出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//A中每个任务都带有3个属性t, p, d,分别表示任务的运行时间,利润以及截止时间。
K-PROFIT-DEADLINES'(A, n, k)
sort A[1 : n] by attribute d
T = 0
for i = 1 to n
T = T + A[i].t
let f[0 : n, 0 : T] be a new table by 0
for i = 1 to n
for j = 1 to T
f[i, j] = f[i - 1, j]
A[i].d = min{A[i].d, T}
for j = A[i].t to A[i].d
f[i, j] = min{f[i, j], f[i - 1, j - A[i].t] + A[i].p}
return f[i, T] >= k

由于每个任务的运行时间不超过 n,因此 Tn2。因此算法 K-PROFIT-DEADLINES' 的时间复杂度为 O(nT)=O(n3),它是多项式的。

d

题目 34-c 的动态规划算法即可直接计算出最大利润值。修改后的程序为 PROFIT-DEADLINES,它的时间复杂度同样为 O(n3)

1
2
3
4
5
6
7
8
9
10
11
12
13
PROFIT-DEADLINES(A, n)
sort A[1 : n] by attribute d
T = 0
for i = 1 to n
T = T + A[i].t
let f[0 : n, 0 : T] be a new table by 0
for i = 1 to n
for j = 1 to T
f[i, j] = f[i - 1, j]
A[i].d = min{A[i].d, T}
for j = A[i].t to A[i].d
f[i, j] = min{f[i, j], f[i - 1, j - A[i].t] + A[i].p}
return f[i, T]