2、嵌套箱問題
2
、一個d 維箱(x1,x2,...,xn)嵌入另外一個d 維箱
(y1,y2,...,yn)
是指存在1,2,…,d 的一個排列π,使得
xπ(1)<y1 ,xπ(2) <y2, ... , xπ(d)<yd
。
1)
證實上述箱嵌套關係具備傳遞性;
2)
試設計並實現一個貪心算法,用於肯定一個d維箱是否可嵌入另外一個d維箱;
3)
給定由n 個d 維箱組成的集合
{ B1,B2,B3,...,Bn}
,試設計並實現一個貪心算法找出這n 個d維箱中的一個最長嵌套箱序列,並用n和d 描述算法的計算時間複雜性。
1)
箱嵌套關係的傳遞性
證實:
設有
3
個
d
維箱
B1(x1 , x2 ,
...
, xd)
,
B2 (y1 , y2 ,
...
, yd)
,
B3(z1 , z2 ,
...
, zd)
,
B1
可嵌入
B2
,
B2
可嵌入
B3
。
B1
可嵌入
B2
,則存在排列π使得:
xπ(1) < y1
,
xπ(2) < y2
,...,
xπ(d) < yd
——
1
B2
可嵌入
B3
,則存在排列θ使得:
yθ(1) < z1
,
yθ(2) < z2
,...,
yθ(d) < zd
——
2
由
1
式可得:
xθ(π(1)) < yθ(1)
,
xθ(π(2)) < yθ(2)
,...,
xθ(π(d)) < yθ(d)
——
3
由
2
3
可得:存在排列
λ = θπ
使得:
xλ(1) < z1
,
xλ(2) < z2
,...,
xλ(d) < zd
根據d維箱的定義可得,
B1
可嵌入
B3
。所以,嵌套箱關係具備傳遞性。
2) d
維箱的嵌套關係
■
貪心選擇性質
:
對於d維箱X
(x1 , x2 ,
...
, xd),Y (y1 , y2 ,
...
, yd),
排列
π
、
θ
是分別使
X
、
Y
非遞減有序的排列,有以下
結論:X→Y(表示X可嵌入Y)的充要條件是,對任意1≤i≤d有
x
π(i)
< yθ(i)
。
證實
:
a.
充分性
:
當
對任意1≤i≤d有
x
π(i)
< yθ(i)
時,令
λ = πθ-1,
那麼
x
λ(i)
=
x
π(θ
-1
(i))
< yθ(θ-1 (i)) =
yi
,
即存在一個排列
λ
使得對於
任意1≤i≤d,
x
λ(i)
<
yi
,因此
X
→Y。
b.
必要性:
用數學概括法證實。
當維數爲1時,X→Y 可得
x1
<
y1
,
那麼
x
π(1)
< yθ(1)
成立
。
假設維數爲
d
時,結論成立,即
:
當X→Y時,對於任意1≤i≤d,有
x
π(i)
< yθ(i)
。
那麼當維數爲
d + 1
時,
對於任意1≤i≤d+1,X→Y,則存在
λ
使得
:
xλ(1) < y1
,
xλ(2) < y2
,
...,
xλ(d) <yd
,
xλ(d+1) <yd+1
——
1
先觀察
1
式前
d
項
,
xλ(1) < y1
,
xλ(2) < y2
,
...,
xλ(d) <yd
。
由假設可知,對任意1≤i≤d,有存在排列
π
、
θ
使得
x
π(i)
< yθ(i)
,
即
:
x
π(
1)
≤
x
π(
2)
≤
...
≤
x
π(
d)
——
2
y
θ(
1)
≤
y
θ(
2)
≤
...
≤
y
θ(
d)
——
3
x
π(1)
< yθ(1)
,
x
π(2)
< yθ(2)
,...,
x
π(d)
< yθ(d)
——
4
此時,
π
、
θ
只對
1
式前
d
項進行排列,並不包含
xλ(d+1)
和
yd+1
。能夠將
xλ(d+1)
按大小順序插入到
2
式
(
設插入位置爲
j)
,從而有新的排列
π’
使得
xi
(
1
≤i≤d+1
)
非遞減有序。
同理,也有
θ’
使得
yd+1
按大小順序插入到
3
式後
(
設插入位置爲
k)
,
yi
(
1
≤i≤d+1
)
非遞減有序。
由於
xλ(d+1) <yd+1
,
易知
j
≤
k
。
當
j = k
時,由於
x
m
、
ym
(
1
≤m≤d+1
)
的對應位置都沒有變,
顯然
x
π’(i)
< yθ’(i) (
1
≤i≤d+1
)
,
所證結論成立。
當
j<k
時,
x1<y1
,
x2<y2
,...,
xj<xj+1<yj
,
xj+1<xj+2< yj+1
,...,
xk-1<xk< yk -1
,
xk<yk -1 < yk
,
xk+1<y k+1
,...,
xd+1< y d+1
。
即
,
對任意1≤i≤d+1
x
π’(i)
< yθ’(i)
,
所證結論成立。
命題得證。
■
算法實現
由上面所得結論,對兩個
d
維箱進行排序後,只要判斷排序後兩個
d
維箱的嵌套關係就能夠得出結果。
-----------------------------------------------------------------------------------------
求兩個箱子的嵌套關係的僞代碼
:
返回
1
表示
X
嵌套
Y(
即
Y
→
X)
返回
–1
表示
Y
嵌套
X(
即
X
→
Y)
返回
0
表示
X
和
Y
之間無嵌套關係
NEST(X , Y , d):
Sort(X)
▹對數組所表示的
d
維箱
X
、
Y
進行排序
Sort(Y)
if X[0] > Y[0]
then for i ← 1 to d – 1
do if X[i] <=Y[i]
then return 0
return 1
else for i ← 0 to d – 1
do if X[i] >=Y[i]
then return 0
return –1
--------------------------------------------------------------------------------------
■
時間複雜度分析
NEST()
的主要時間消耗在於排序,使用快速排序時,
NEST()
的時間複雜度爲
: O(d lgd)
。
■
算法測試
對應的算法實現
Java
源文件爲
NestedBox.java
輸入:
X(1,6,2,5,9)
,
Y(7,4,8,19,32)
輸出
: Y
嵌套
X
3)
最長嵌套箱序列
■
算法思想
將
n
個
d
維箱之間的關係用一棵樹來表示,其中可嵌套其它箱子的箱子爲父節點,被嵌套的箱子做爲孩子節點,無嵌套關係的節點爲兄弟節點。這樣就一個
d
維箱的深度值就是在這棵樹中的深度。
深度值的遞歸定義以下
:
只要找出深度最大的節點,而後遞歸地輸出它嵌套的箱子,結果就是最長嵌套箱序列。
■
貪心選擇性質
假設最長
d
維箱序列的一個最優解是
B1 , B2 , …,Bk (k>1),
其對應的深度值分別爲
H1, H2 , …, Hk (H1 > H2…> Hk)
。
a.
若
H1
爲最大的深度值,則說明問題的最優解以一個貪心選擇開始。
b.
若
H1
不是最大的深度值,不妨設
H1<Hj (1<j
≤
k)
。但
B1
嵌套
Bj
可得
H1 >Hj
。與假設矛盾。因此
H1
爲最大的深度值,這說明問題的最優解以一個貪心選擇開始。
■
最優子結構性質
設嵌套序列
B1 , B2 , …,Bk (k>1)
是問題的一個最優解,各個箱子的深度值爲
H1, H2 , …, Hk (H1 > H2…> Hk)
。由貪心選擇性質可知
H1
爲最大深度值,其他箱子組成的序列
B2 ,B3 , …,Bk (k>1)
是在全部箱子中去掉
B1
及與其具備相同深度值的箱子後,在剩下的箱子中查找最長嵌套箱序列的一個最優解。所以,最長嵌套箱序列問題具備最優子結構性質。
■
算法實現
--------------------------------------------------------------------------------------
求最長嵌套箱序列的僞代碼
:
B
爲存放
n
個
d
維箱的二維數組
Longest(B , n , d):
▹
A
存放各箱子嵌套關係的二維數組
,
下標從
0
開始
,
列數爲
n+1.
▹
A[i,n]
表示箱子
i
的深度值
▹
初始化
A
數組
for i ← 0 to n
do A[i , n] ← 0
▹
計算嵌套關係
for i ← 0 to n – 1
do for j ← i+1 to n – 1
do A[i , j] ← nest(B[i] , B[j] , d)
A[j , i] ← – A[i , j]
▹
遞歸地修改嵌套的深度值
for i ← 0 to n – 1
do for j ← 0 to n – 1
if A[i , j] = – 1
then addHeight(A , n , i , j)
▹
查找深度值最大的箱子做爲首嵌套箱
maxBoxIndex
←
findMax()
▹
輸出最長嵌套箱序列
trace(maxBoxIndex)
--------------------------------------------------------------------------------------
遞歸地修改嵌套箱的深度值
addHeight(A , n , i , j):
if A[i , n] = A[j , n]
then A[j , n]
←
A[j , n] + 1
for k
← 0 to n – 1
do if A[j , k] = – 1
then addHeight(A , n , j , k)
--------------------------------------------------------------------------------------
查找深度值最大的箱子做爲首嵌套箱
findMax(A , n):
max
← A[0 , n]
maxBoxIndex
← 0
for i
← 0 to n – 1
do if A[i , n] > max
then max
← A[i , n]
maxBoxIndex
← i
return maxBoxIndex
--------------------------------------------------------------------------------------
根據深度值最大的箱子
,
輸出最長嵌套箱序列
trace(n , maxIndex):
while A[max][n] > 0
do seq
← (max+1) + 「
→
」 + seq
m
← 0
for i
← 0 to n – 1
do if A[max , i] = 1 and A[i , n] >=m
then m
← A[i , n]
temp
← i
max
← temp
seq
← (max+1) + 「
→
」 + seq
print seq
--------------------------------------------------------------------------------------
■
時間複雜度分析
:
算法的主要時間消耗在於
Longest()
中
計算嵌套關係的時候,其中
nest()
算法的時間複雜度爲
O(d lgd)
。因此總時間複雜度爲
:
O(n2 d lgd)
。
■
算法測試
:
相應的算法實現文件爲
LongestNestedBox.java
輸入數據
: (8
個
6
維箱
)
{5, 2, 20, 1, 30, 10},{23, 15, 7, 9 ,11, 3},
{40 ,50 ,34 ,24, 14, 4},{9 ,10, 11 ,12, 13, 14},
{31, 4 ,18, 8 ,27, 17},{44, 32, 13, 19 ,41, 19},
{1 ,2, 3 ,4 ,5, 6},{80, 37 ,47 ,18 ,21, 9}
輸出數據
: (
輸出數據中的數字表明按順序輸入的箱子,編號從
1
開始
)
最長嵌套箱序列
:7
→
2
→
5
→
6