迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。迭代法又分为精确迭代和近似迭代。“二分法”和“牛顿迭代法”属于近似迭代法。5 s1 O! T E5 M- g9 v! y
# c3 b. c; \/ Z" n' \+ F+ \ 迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。 5 f1 Y3 T( ^% _- v2 h9 X/ E# D ) `; f& K, s( e+ _ 利用迭代算法解决问题,需要做好以下三个方面的工作: 4 m9 y* c6 K, r5 T e- Z/ {* W8 t5 P/ [. P% t7 u* o
一、确定迭代变量。在可以用迭代算法解决的问题中,至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。 k4 f2 L2 T2 H0 b. } - _5 e5 l- z0 ~" X 二、建立迭代关系式。所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。 0 P& q S% G5 e
; q8 o6 i3 T+ l$ @: T1 O/ s
三、对迭代过程进行控制。在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地重复执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析出用来结束迭代过程的条件。 - ?( M& o# \" Z
' q D$ Q: k- n
例 1 : 一个饲养场引进一只刚出生的新品种兔子,这种兔子从出生的下一个月开始,每月新生一只兔子,新生的兔子也如此繁殖。如果所有的兔子都不死去,问到第 12 个月时,该饲养场共有兔子多少只? ; \ R n2 L# {, T0 z- t; m
2 s1 l8 y# Q; f* u
分析: 这是一个典型的递推问题。我们不妨假设第 1 个月时兔子的只数为 u 1 ,第 2 个月时兔子的只数为 u 2 ,第 3 个月时兔子的只数为 u 3 ,……根据题意,“这种兔子从出生的下一个月开始,每月新生一只兔子”,则有 ' x1 P; B1 D$ t1 E( E2 x ! X. P6 G% O* ?" a0 ` u 1 = 1 , u 2 = u 1 + u 1 × 1 = 2 , u 3 = u 2 + u 2 × 1 = 4 ,…… ! A4 l* S7 W1 j6 `# D+ p
+ b9 m% A5 H! Y+ N; z+ o
根据这个规律,可以归纳出下面的递推公式: 5 s! \- p! H* n, ^1 E( t) k6 _8 V" N; B
u n = u n - 1 × 2 (n ≥ 2) 9 @$ ?8 V- F* m( p" w * ~2 Z% a. t4 s6 r" _ 对应 u n 和 u n - 1 ,定义两个迭代变量 y 和 x ,可将上面的递推公式转换成如下迭代关系: , a* b# d( a5 [1 t
" g" ]- `+ x4 M0 A$ I( ^* O* e; N8 s
y=x*2 + j4 s m9 y/ H8 F
4 B0 r! g9 ` ^* \- Q8 X
x=y ( d7 B, M* d! U9 G! X& W4 ~4 ]# _; r/ H. i8 V
让计算机对这个迭代关系重复执行 11 次,就可以算出第 12 个月时的兔子数。参考程序如下: " P$ S% M* `: M! f y, e# ] 1 T: i$ e4 k$ S. [6 ] cls 1 [* k; ?" W& H% h; L
7 M: L8 Z! a1 ]6 @; n& H! s
x=1 ! M0 l% S6 k5 E) m. Z) ~4 h 5 S! z, L1 V: w* v0 { for i=2 to 12 * k4 {9 w& v1 t/ ?% U $ s. P' p; c' U8 g0 D y=x*2 ( r& d. N: k; e* G' T2 g; y9 C. I. Y: T, @4 g8 g
x=y 6 V+ s" f& w3 D% J0 K# F
7 G( b' i9 \ z2 N6 I# Q5 i1 A
next i & @- }8 N2 h6 o0 c( u1 Y- X7 h4 C5 \3 r( \
print y $ q) x; ?, k1 g9 E/ @/ G9 E6 k
. B0 {3 K. K4 N6 V- W5 V end r/ s& A" P9 f, i ( y8 Q# t9 |% h* ~% @# B% d 例 2 : 阿米巴用简单分裂的方式繁殖,它每分裂一次要用 3 分钟。将若干个阿米巴放在一个盛满营养参液的容器内, 45 分钟后容器内充满了阿米巴。已知容器最多可以装阿米巴 220,220个。试问,开始的时候往容器内放了多少个阿米巴?请编程序算出。 6 [3 ^; @* ?6 K: T8 e B. u$ r1 D/ I+ y% o* ?
分析: 根据题意,阿米巴每 3 分钟分裂一次,那么从开始的时候将阿米巴放入容器里面,到 45 分钟后充满容器,需要分裂 45/3=15 次。而“容器最多可以装阿米巴2^ 20 个”,即阿米巴分裂 15 次以后得到的个数是 2^20 。题目要求我们计算分裂之前的阿米巴数,不妨使用倒推的方法,从第 15 次分裂之后的 2^20 个,倒推出第 15 次分裂之前(即第 14 次分裂之后)的个数,再进一步倒推出第 13 次分裂之后、第 12 次分裂之后、……第 1 次分裂之前的个数。 : A* ?- Y, q4 D z9 U ~8 I4 m+ F4 K0 n8 D; T1 P 设第 1 次分裂之前的个数为 x 0 、第 1 次分裂之后的个数为 x 1 、第 2 次分裂之后的个数为 x 2 、……第 15 次分裂之后的个数为 x 15 ,则有 2 I) R$ s1 f+ n y5 P
( I" V+ ^: M6 H0 U* m/ m6 ~4 j x 14 =x 15 /2 、 x 13 =x 14 /2 、…… x n-1 =x n /2 (n ≥ 1) 5 |1 D; D' m) I- H) z* O1 {
- z) R. C; J# J- ]1 P 因为第 15 次分裂之后的个数 x 15 是已知的,如果定义迭代变量为 x ,则可以将上面的倒推公式转换成如下的迭代公式: 0 S4 R; b% q( ]6 i f# t
$ U8 L: L7 [- C' h/ I* S2 j% v
x=x/2 ( x 的初值为第 15 次分裂之后的个数 2^20 ) 5 g% v# y* k4 |8 n) v1 W6 W5 K) T9 N- h" a
让这个迭代公式重复执行 15 次,就可以倒推出第 1 次分裂之前的阿米巴个数。因为所需的迭代次数是个确定的值,我们可以使用一个固定次数的循环来实现对迭代过程的控制。参考程序如下: , R3 h# |3 K* Z- K! j: C7 S! O
! f0 l1 z: @' G+ I' }" r
cls " l3 d& c; `5 V/ u2 q- Z
% F8 X% k0 P8 @6 U' K x=2^20 : q9 l) h1 {8 _: G: b# f
- H1 B7 G9 ]" e( b+ M B& O for i=1 to 15 / Q) B3 Y% g/ n$ h 0 \: x6 Y" H+ h/ r; ~$ v x=x/2 1 U* c1 H: `% ~ E4 l' H2 L3 [$ D/ M& B0 ~ t
next i P; n7 k8 a& q$ F( t: H % ^) A1 x2 ?, S. n% _ print x - Q# L6 _: S+ k5 B4 `/ I
5 r, U5 S7 x% f3 U end- g$ H0 N' q5 b9 y9 c6 K! x
" v3 G& x H4 l$ K0 h" [ ps:java中幂的算法是Math.pow(2, 20);返回double,稍微注意一下 + X% U; w/ e1 p: S) I' B " S8 g0 |6 J% q7 c 例 3 : 验证谷角猜想。日本数学家谷角静夫在研究自然数时发现了一个奇怪现象:对于任意一个自然数 n ,若 n 为偶数,则将其除以 2 ;若 n 为奇数,则将其乘以 3 ,然后再加 1 。如此经过有限次运算后,总可以得到自然数 1 。人们把谷角静夫的这一发现叫做“谷角猜想”。 ' o! f) K# I7 T/ [ R; ]2 J1 Q7 h1 o( a3 x$ W% a% Q
要求:编写一个程序,由键盘输入一个自然数 n ,把 n 经过有限次运算后,最终变成自然数 1 的全过程打印出来。 5 y& y% M5 z% L " D8 c) ^/ d& v9 w( f 分析: 定义迭代变量为 n ,按照谷角猜想的内容,可以得到两种情况下的迭代关系式:当 n 为偶数时, n=n/2 ;当 n 为奇数时, n=n*3+1 。用 QBASIC 语言把它描述出来就是: ' z% i$ e$ {* {1 {6 ^. l& O
/ e S0 f6 K; s5 M/ n
if n 为偶数 then e' S" t: s0 O5 _; l( J4 W- h1 g8 `! w2 ]3 d& \0 g
n=n/2 , _4 x b- F; J6 H3 J
j6 z. s. U4 P3 s. {; q; m else 0 o' G* W) u R, l" H
: y% D# p+ v7 ]9 {/ ^3 o v4 F
n=n*3+1 4 i- G! I# N# C3 ?$ o
$ {- _9 u6 X' R/ w
end if & {- {- W. e8 C' t5 j7 s1 q, o
4 n8 T; T: u1 x) v 这就是需要计算机重复执行的迭代过程。这个迭代过程需要重复执行多少次,才能使迭代变量 n 最终变成自然数 1 ,这是我们无法计算出来的。因此,还需进一步确定用来结束迭代过程的条件。仔细分析题目要求,不难看出,对任意给定的一个自然数 n ,只要经过有限次运算后,能够得到自然数 1 ,就已经完成了验证工作。因此,用来结束迭代过程的条件可以定义为: n=1 。参考程序如下: 8 O8 ?9 |- g; N2 D$ f. j X5 _) U2 n/ l7 Z9 Z' a7 s! x7 s1 a
cls 9 y1 A6 ]; h, a& D' @/ o3 ^ ' ~! p, Q) z4 Z' V P- q- L0 G input "Please input n=";n + x+ u8 k/ O! t |# d
, G# v1 k& r6 K% X: j) r* w
do until n=1 0 J- U$ j9 v* C+ A8 i _, { 0 u) o2 u6 ` o7 h% \% ]7 ` if n mod 2=0 then 7 h; l- P. l$ C$ p" a( H$ r) a: \) m& h3 V* G( D5 ]2 X6 C
rem 如果 n 为偶数,则调用迭代公式 n=n/2 7 U6 K( z) X1 D4 _; G6 ]' L& R* C8 V4 k9 v
n=n/2 " ]$ m" A8 N0 b; o# F; d
, E. z5 T/ J/ h o- y
print "—";n; 4 J; L! [+ u; |4 ?% x/ A
# L0 z' b& c/ s
else 9 O; C, A3 \ C) j1 r* S+ N! _; r/ G/ ^6 Q
n=n*3+1 1 E" g. n! s" y8 e) H4 L 6 ^ V1 J! u. _ print "—";n; 1 t7 V z) ?3 y/ I! v2 o, V
' }" f0 b- M& Q" b end if 4 X/ P$ \- r, _/ L/ B- j+ d
) b% U/ n$ [: S: | loop * n: C G8 Q/ O
- E1 I6 k2 k1 `6 q end ) @# {% h; ~1 Q' h. a
6 s8 f: W0 ]$ H+ G$ H5 N 迭代法 ( r; d1 a6 Y" ?4 m' t% ?: _ & a( Y/ ^6 _) ]: R. T2 G _ 迭代法是用于求方程或方程组近似根的一种常用的算法设计方法。设方程为f(x)=0,用某种数学方法导出等价的形式x=g(x),然后按以下步骤执行: ' T( r! R) X6 l: g( Y6 ]
, d- M! G1 U3 s% ~
(1) 选一个方程的近似根,赋给变量x0; 6 ~2 z# j" L" i( D; y# u2 u. m
$ z. M3 w* D2 L7 K1 U; |
(2) 将x0的值保存于变量x1,然后计算g(x1),并将结果存于变量x0; # ]% B( l/ F h
2 R& j/ N1 l. ]& ?9 F6 I0 P* O (3) 当x0与x1的差的绝对值还小于指定的精度要求时,重复步骤(2)的计算。 ' z/ Y9 N/ q/ Q1 `" S
8 j5 I6 k" w* I
若方程有根,并且用上述方法计算出来的近似根序列收敛,则按上述方法求得的x0就认为是方程的根。上述算法用C程序的形式表示为: / M0 j7 v9 d" c3 a% Z
; |8 e/ v4 G: A+ M2 I! d 【算法】迭代法求方程的根 - o, ~# H# \3 H( ]" ]- j9 l% { |4 i, ?" e$ l! g) R: f7 w
{ x0=初始近似根; - T, |! ~% D; z# N6 u a" K
a: R) ?- D: ?* \1 j9 @, G V/ k do { . K- P" r& N3 }0 A
/ o8 T# P a; q/ Z x1=x0; 7 t; j& k& R s. ?9 b' c) i3 ^* L 4 Q; N, T( l% D+ Q x0=g(x1); /*按特定的方程计算新的近似根*/ + N" i/ R2 e. d" i; E+ R ' b* o/ W* e& I } while ( fabs(x0-x1)>Epsilon); . S8 B: h( V4 x& B8 M 8 t! s8 Z# o, F7 k8 ?0 f printf(“方程的近似根是%f\n”,x0); 3 o. @8 O/ K8 y! X9 i1 S* @6 m
2 R/ K8 P7 l/ O- q/ {9 c
} ; ^% _7 k/ x% W4 ~7 v 9 d0 T" \5 h0 P; L 迭代算法也常用于求方程组的根,令 5 g: c2 b# f3 ?4 n1 X" t $ J m# E' m, P& j9 Y: V( E6 f, v# q X=(x0,x1,…,xn-1) 5 W" w. Z, S W/ W/ I
' M$ R r7 I" \4 Q/ f 设方程组为: 3 k6 T* n8 E; u5 G# o) ]6 D0 k. p" ]! K4 @
xi=gi(X) (I=0,1,…,n-1) , p& P# M: x3 m5 L 7 Y! P* [9 U/ I% D8 Y$ w 则求方程组根的迭代算法可描述如下: ; ]/ c; f% h! s f5 I- N3 Y7 i- i
# v9 e A' y7 `# { 【算法】迭代法求方程组的根 : c/ ?5 f5 ?& `, S% [/ s1 x
6 l& H" j% |# t { for (i=0;i 6 r) O& p3 o1 I& K6 x, f& ?- r3 U3 j( k% T0 _1 o; C
x=初始近似根; 5 P8 a! ~0 M4 Q O6 u% V4 m7 W" g
do { 8 x6 U( L+ G* u0 |* x2 C
* o9 I2 Y/ P& x8 J8 o
for (i=0;i ( }% Y# B0 q0 @) g' K8 M% q/ z5 m4 V, ^: Z. W7 r
y=x; ; C: J5 l/ w3 q5 o. Y! E3 j & S0 q2 h, t7 t& a, ~ for (i=0;i 6 A. {! U& V: V7 [/ `9 ^; I: g
7 g7 x4 p$ S* I x=gi(X); 3 n! w4 e7 E) C; I . W5 o) D/ S2 b! V for (delta=0.0,i=0;i 6 ]9 m z9 _% V. I: }" @ ' m; _! A$ Y6 \9 J* y- ? if (fabs(y-x)>delta) delta=fabs(y-x); ' Y/ _; v1 p! H5 D6 C2 T 4 v2 ?6 P4 G2 J1 c7 @* n% l } while (delta>Epsilon); D1 ]- ~! ~/ i! {
1 g0 v3 z7 y( P- l3 `/ j! E
for (i=0;i 0 u( t$ z9 ^) h5 ~9 U F, O: d 0 F0 P) y& G; ^+ Y! p printf(“变量x[%d]的近似根是 %f”,I,x); ; n- |0 P6 a5 z& Z1 E7 a
6 \0 E, ?) M' f: J3 q5 f4 [. P printf(“\n”); " d3 M; C( `2 e
z7 x6 R U; |( i& e 递归是设计和描述算法的一种有力的工具,由于它在复杂算法的描述中被经常采用,为此在进一步介绍其他算法设计方法之前先讨论它。 9 [: W6 ~9 {0 j& `# }# p d
+ {3 E% g8 L' A) d/ z- e7 X2 ]
能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。 ( L ` f8 Q- ^. M% T, K
; M( |, U+ X' }) l } 3 k' ^8 I+ b# J6 ^( @ * z# j) N! G. h: ?2 Q void main() ! V% c( ` j- q4 X" `* k: w, ]- T1 T2 d% k
{ a[0]=3; , W3 v2 t! {6 v4 G, ?! K( U: O 3 ^/ ~3 o2 s' b: h comb(5,3); 6 D7 `. x/ L" T$ e4 e' b % J0 M" u' |* _) c; q9 r } $ O3 {) Z6 \: L6 \( c# k& @0 w$ f0 n2 a' v q
【问题】 背包问题 9 T2 Q' K( [& i6 Y' ~- ?
5 G5 b. A& f9 q0 U2 h 问题描述:有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物品的选择方案,使选中物品的总重量不超过指定的限制重量,但选中物品的价值之和最大。 ' t9 P0 r+ S+ w' j
# {4 ]3 z* g2 _4 i 设n 件物品的重量分别为w0、w1、…、wn-1,物品的价值分别为v0、v1、…、vn-1。采用递归寻找物品的选择方案。设前面已有了多种选择的方案,并保留了其中总价值最大的方案于数组option[ ],该方案的总价值存于变量maxv。当前正在考察新方案,其物品选择情况保存于数组cop[ ]。假定当前方案已考虑了前i-1件物品,现在要考虑第i件物品;当前方案已包含的物品的重量之和为tw;至此,若其余物品都选择是可能的话,本方案能达到的总价值的期望值为tv。算法引入tv是当一旦当前方案的总价值的期望值也小于前面方案的总价值maxv时,继续考察当前方案变成无意义的工作,应终止当前方案,立即去考察下一个方案。因为当方案的总价值不比maxv大时,该方案不会被再考察,这同时保证函数后找到的方案一定会比前面的方案更好。 % x3 A3 R. o, C5 l
# M7 B+ `' j4 w 对于第i件物品的选择考虑有两种可能: 1 @2 I8 C. U- b, T3 M
' H. C4 X" q$ A* C 按以上思想写出递归算法如下: 5 m; d# h$ b/ s: O3 P# O. Q0 H, M$ `! t. h( H" i
try(物品i,当前选择已达到的重量和,本方案可能达到的总价值tv) H$ B7 L; f9 z+ z1 S 0 A2 u/ B/ o8 A' ~; { { /*考虑物品i包含在当前方案中的可能性*/ ; h* \. w* k9 z- {+ J ! q6 t, L+ O$ \* D+ [, P if(包含物品i是可以接受的) + y; r) `( v5 A! ?. n; }5 I# W
! f+ q4 q+ V9 {8 _% h { 将物品i包含在当前方案中; : l4 o; B5 u f; H. x5 y
# E5 z& B/ |' H C$ a if (i ( ~8 f9 G7 z; d8 R: `; y A
( }! D3 l! Q/ R/ ~) q- N( S1 L
try(i+1,tw+物品i的重量,tv); 9 ]4 U- s" G( g+ g* s/ s5 Y4 d2 e, p$ O& j: t! W ?
else 5 g: [ V+ i; y# y' }4 O h
* F; o9 s7 @% }8 P' p) n, W" h r8 q
/*又一个完整方案,因为它比前面的方案好,以它作为最佳方案*/ % d4 O+ G- g8 e! ^/ A/ a
' [( }0 U% [2 o
以当前方案作为临时最佳方案保存; & Z9 v6 x$ J$ D$ E, e' Z. w
: z6 o7 n# E3 h4 r, x) \ 恢复物品i不包含状态; A+ E& }& u5 Q4 I+ Z* E
' v# c) D2 x5 d: J, G) b
} / E% ]; W6 B; i3 }
1 e, |; ^. y' p6 g j; {& _
/*考虑物品i不包含在当前方案中的可能性*/ 2 n3 b% t8 W8 y1 z 4 G, \, ~: ?& K7 U if (不包含物品i仅是可男考虑的) / t2 M% m( x7 Y5 P* e" ^+ i2 V6 |
3 F" Z) J4 T: `& x if (i Z P& f9 q1 Y6 U, l 7 d- t3 f5 e* [ try(i+1,tw,tv-物品i的价值); : H/ j! Y* A! ]: ]8 y1 _
3 f# R9 d/ A: o; g2 X9 M) Y. }' E x
else ' r- ^- r |# C, ?( a + ~* y3 @8 D4 I ~5 ^4 U- P /*又一个完整方案,因它比前面的方案好,以它作为最佳方案*/ 2 [! Y7 X' {' z5 @+ X. `1 G
$ }0 _ ^; n' z 以当前方案作为临时最佳方案保存; 8 }) x3 R8 U1 [; v5 ~
2 N- Q) g; Y: M
} 6 c" k; J# R6 x2 b
; D w' K- ?1 V ~% _; m0 d
为了理解上述算法,特举以下实例。设有4件物品,它们的重量和价值见表: ! n( E: a& E- t4 [/ j' Z S F
% _! I2 ~4 _9 g& f1 `% r& y' s
物品 0 1 2 3 : @% s0 Y& U2 x- h% t; S, M. J" n8 n
7 t8 k- R8 T7 P5 U
重量 5 3 2 1 : Q" K: }2 V- P C2 W* }% g
4 K9 O) X# h, ], b
价值 4 4 3 1 1 w# d1 w/ H' m, A
2 f& T* `9 g7 Z& ]& F: h
并设限制重量为7。则按以上算法,下图表示找解过程。由图知,一旦找到一个解,算法就进一步找更好的佳。如能判定某个查找分支不会找到更好的解,算法不会在该分支继续查找,而是立即终止该分支,并去考察下一个分支。 / C8 W$ P2 m+ l5 y. M6 u# e $ Y) V5 B1 h f3 y( [' n 按上述算法编写函数和程序如下: % I$ @9 N U# j( Z3 I, | q% G" r8 h, E
【程序】 w5 j$ M3 A4 n, c $ c9 ?( J. r! N& ^ # include % l( q3 B4 v+ ?; _5 h9 q9 x) o$ D7 }4 a" x$ A. Q Z6 J
# define N 100 7 N' s# |, ]: T- `3 A* A( k
% v: V% k1 ~' H* v
double limitW,totV,maxV; 9 w7 t3 ]$ h6 j* z$ v
O) K& Z- K1 _( P! C5 F
int option[N],cop[N]; 5 A* l2 l r: L$ N' `/ j* }0 B% F
( r3 j! R2 R; ^3 j5 m) Q% e struct { double weight; " o8 t& w9 T. `7 y+ x: p* N- F5 Q. W G5 j( S( H
double value; . A3 Z) H P2 N( V0 [4 @& Q4 k7 |
}a[N]; & V1 | m+ m( b# {9 ?; |3 D. F
5 K9 Q% W3 E+ K
int n; 0 Q- P/ X/ D7 v, Q$ g8 O
3 j- M$ g) @) |! P9 d5 k) ? void find(int i,double tw,double tv) & O7 L4 `* e/ _2 U, F) x4 W$ R$ o1 O' c6 H
{ int k; 7 x6 u. O t5 J; x) U4 M1 Z+ O
1 K8 d+ K7 s. k0 K1 c4 {
/*考虑物品i包含在当前方案中的可能性*/ 4 o* ?8 \& P( m9 V8 h( M- K( j* c" Y; l4 M) \
if (tw+a.weight<=limitW) % `4 B L- X# z. Z* n& m0 p' P7 Q) r1 g7 z' u+ K/ u4 `1 q
{ cop=1; " B0 x, @: `' V% j1 p& y9 W0 [( h 4 f( u& V& a4 c! |1 a: ?/ x! @* a+ Y V if (i ! f+ M0 A6 w9 u3 `8 E2 r* r. a/ B+ |* ]" n2 P
else 4 {" k6 L. h- V% w% e" x 6 X: r& |5 W% w/ j" N- ~+ o( Y { for (k=0;k 4 I( }0 x7 f* O0 ^, o7 Q
; |$ W5 p! q3 W option[k]=cop[k]; 0 `/ z' a) R& O8 y
# N! U _7 T, y6 z) H: U4 |
maxv=tv; 9 \1 F0 P6 w! O7 c) Y) u2 m7 x& |/ g8 Y2 I" w. `
} . `# J- V% {& ?) \' V! [+ _( Z% ~- {1 ]9 B5 u! I; i+ l
cop=0; / | @. A, `% x- S/ @2 g * _& L! P/ e. i9 n5 S8 _ } a' w6 z- B% S
* b' V+ \1 u8 [8 L" p
/*考虑物品i不包含在当前方案中的可能性*/ ! R) l" J: Y" N2 Z0 i* ?4 l9 O 5 l# e: C" S2 M' M* Q2 X, w if (tv-a.value>maxV) 8 s$ p4 s. t3 u; \" Z3 E# c
2 u d% W1 Z: {$ N& q
if (i 3 U* w& G9 c) g2 Y* @- P / j- H, u" y; I else ! N7 B( D' I$ H2 e% l1 d _; G2 F2 E( f3 M8 H4 s3 Z9 a9 a
{ for (k=0;k ; @0 `. u4 C7 } , F t" `9 H8 H7 H option[k]=cop[k]; ) T1 F( ?. W/ V! O0 A5 X
9 h6 i( ]8 ]6 n9 c; x( c maxv=tv-a.value; 8 M; [* v( b: W. z
# ?. A8 |+ ?2 @$ N
} 4 f+ E' S) f5 ^1 T9 N, |
+ ], m) j2 `2 q/ B5 c( G9 w
} " t: W5 u9 R2 F) \ 1 J0 [% o( X/ L void main() ; |" v- b5 y& n% ?# w; O; n( i
1 j9 _. D3 g' E( z, A- o$ K) Z { int k; 5 C" `. M- t; L0 Q; F) i z5 k2 g l$ e$ h( q- o3 A
double w,v; 3 ? a# z0 v5 b+ q( p6 Q
F1 _5 w' V1 e( h: j4 B* A" i
printf(“输入物品种数\n”); 0 A d0 _4 o" Q2 G3 k6 B$ i
$ `7 M6 ~8 ]; u, { scanf((“%d”,&n); 2 {2 g8 p$ ~. x2 s7 X7 ^4 T" T
6 T4 T9 q9 N' X0 d& h" a" s
printf(“输入各物品的重量和价值\n”); 7 q9 `& t8 G1 Z- }. k* d
0 a$ c9 ~- r o: u% Q$ t9 v
for (totv=0.0,k=0;k / A% K' G' k- }) }
. T: i$ o+ ` U5 c/ Y i$ J { scanf(“%1f%1f”,&w,&v); 9 H, j8 Q9 r) q5 s9 l- F$ f
$ C! C: B( _/ A
a[k].weight=w; : q( X1 |- E2 c' Q ^4 X! L+ N. X' T7 [$ P v a[k].value=v; 3 e. ] r. l& C, o' v+ ^
3 A' f* j9 c3 O; k
totV+=V; " F9 v0 q' {8 _5 d! Q" u A( M D9 {$ Q
} 9 c( y9 j2 d- Y3 J) ~
% i: ^0 R* r) ?- A printf(“输入限制重量\n”); 2 E% l3 v$ I/ j& ^- a: ^" d( m8 P: Y7 P( Y% z
scanf(“%1f”,&limitV); 1 e9 G7 K4 I. B$ i. ~4 M. N, s' k8 S( w5 K
maxv=0.0; 4 h' l1 b% N. r* t( a( r* l) ~% ~! s3 i- j3 D
for (k=0;k find(0,0.0,totV); ! i, L5 S# r. N3 d! \( E" A! P5 E6 `2 f1 W
for (k=0;k 1 @8 F) M0 `3 S8 \- ~2 K
' U3 Z2 E0 _) o7 Y if (option[k]) printf(“%4d”,k+1); 2 N; ~9 u8 E# x5 z$ u / G! ?$ L4 b, x; l1 d printf(“\n总价值为%.2f\n”,maxv); & B1 P. c; q( Q5 K' j1 N6 c( t% T/ {( S2 i5 N- U" s
} , I( B9 O2 \/ i# h. u3 y" Y & n+ x/ D$ J- r9 u 作为对比,下面以同样的解题思想,考虑非递归的程序解。为了提高找解速度,程序不是简单地逐一生成所有候选解,而是从每个物品对候选解的影响来形成值得进一步考虑的候选解,一个候选解是通过依次考察每个物品形成的。对物品i的考察有这样几种情况:当该物品被包含在候选解中依旧满足解的总重量的限制,该物品被包含在候选解中是应该继续考虑的;反之,该物品不应该包括在当前正在形成的候选解中。同样地,仅当物品不被包括在候选解中,还是有可能找到比目前临时最佳解更好的候选解时,才去考虑该物品不被包括在候选解中;反之,该物品不包括在当前候选解中的方案也不应继续考虑。对于任一值得继续考虑的方案,程序就去进一步考虑下一个物品。 . }* p5 J, h) a0 B4 B3 g4 B
# I' G% c5 q. {4 V% } 【程序】 . q3 O3 R& v. l `
. O1 `8 a; q; A# L # include 0 j6 \/ ^' Q' i
6 ]# e ^6 _1 Y( Q, i9 f9 Y( ~$ W # define N 100 * A2 B: q; n- ?% z' Q2 T) D2 M' t) O" B9 H8 I3 C' K/ I6 V
double limitW; X8 E3 Q; @, I3 ?6 I# V9 ] ) F! F" s- p8 D) H" c int cop[N]; 9 |, w8 g! `3 g. q# ]; y+ @$ S- c9 o' S) k: \$ q: Y
struct ele { double weight; % M* D% [/ l& J, k+ `9 o, P0 Y. o1 y+ c
double value; 5 J; k e) ^$ p T7 E
6 z# `; C; u+ B } a[N]; ( D3 @' ]2 x% ?- j ~) O2 k
4 _. R t: \* S: `! \
int k,n; 3 S+ ]- C# N$ C# k- D2 o , F: d# e$ ^. T6 @0 n. k- L struct { int ; 3 ?$ ?! t, z& J0 I
2 L& a0 H. g* t, [; S* H9 r' Q2 h double tw; 0 p, |5 e" o5 k4 r0 G
' W1 D& p0 P" w7 o double tv; ) z8 P5 w+ I+ b7 U! }' |% h
4 h/ K; `' Q: k( a0 g) y6 d }twv[N]; $ B8 U: t8 J8 s5 b( X( B! ?/ \
0 R: i' e( c+ {. W4 G' T2 }4 l
void next(int i,double tw,double tv) " i% i" B+ H9 ?# }" y! i3 @+ H& L1 k
9 J6 O: s& c9 A4 J6 l% B# W/ k3 W2 X
{ twv.=1; 8 z% [9 a) h: g( u: q4 Y( O7 ^
. h. d' @, D: v) M2 [ b
twv.tw=tw; . \9 s3 u- I# q, m. Q
4 l4 ~: o* A9 V( g& |
twv.tv=tv; " C& }# w) \1 }, C9 w6 \0 p2 b6 X
/ w! @3 e& t+ x: R: g N* Q3 c8 e
} 4 L4 v! _4 K+ {' n
- B9 |2 H6 S$ R double find(struct ele *a,int n) ' j A6 o" y9 V5 w) H U( W$ P9 _/ `+ N- S) t3 S
{ int i,k,f; ! p; m5 y6 {* I3 B1 t8 \" d0 ]9 `" k9 z& g2 n9 n5 h
double maxv,tw,tv,totv; 0 v6 r) c/ P Q/ g5 \
4 H) c8 O' f5 X5 B! U8 l* G, H maxv=0; + k# y; b% k# x6 G6 S& N