迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。迭代法又分为精确迭代和近似迭代。“二分法”和“牛顿迭代法”属于近似迭代法。 ' C: r8 C& i4 y j6 @8 }/ C# g* _( B/ ` A
迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。 5 Z: D. C# X9 a* U Q F1 j# r
* ~/ ?2 w* O& ? Y2 K& C
利用迭代算法解决问题,需要做好以下三个方面的工作: 1 ^/ r8 m5 a8 L W) [1 z; P; T
E+ i4 |6 C- ^) f! H9 v; B( { 一、确定迭代变量。在可以用迭代算法解决的问题中,至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。 / ^: B, _: K& u" T& R2 z 8 h; C7 X" F( c3 q$ X' z 二、建立迭代关系式。所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。 + s( z6 t6 l1 O2 ^" c; v ; m$ M0 P! J, g 三、对迭代过程进行控制。在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地重复执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析出用来结束迭代过程的条件。 {2 r+ c6 [4 j/ p: @6 N: U' B' M/ L2 a
例 1 : 一个饲养场引进一只刚出生的新品种兔子,这种兔子从出生的下一个月开始,每月新生一只兔子,新生的兔子也如此繁殖。如果所有的兔子都不死去,问到第 12 个月时,该饲养场共有兔子多少只? : T/ M. Y0 }, L& l. c, e
9 P7 K+ [8 J. \$ a/ I7 _7 ]5 Y
分析: 这是一个典型的递推问题。我们不妨假设第 1 个月时兔子的只数为 u 1 ,第 2 个月时兔子的只数为 u 2 ,第 3 个月时兔子的只数为 u 3 ,……根据题意,“这种兔子从出生的下一个月开始,每月新生一只兔子”,则有 " a, s9 \5 B: V) d; ~, K/ p
' z6 Q6 O4 f Z, g u 1 = 1 , u 2 = u 1 + u 1 × 1 = 2 , u 3 = u 2 + u 2 × 1 = 4 ,…… ! T8 Z( ?* W( u6 W) [
- `2 A. D/ o1 }, D2 G3 {& l9 r 根据这个规律,可以归纳出下面的递推公式: ' H0 F& t& V/ _# A! {
7 @3 R- C& L5 {. a
u n = u n - 1 × 2 (n ≥ 2) + `3 ?1 V/ c' r; R6 s 5 F: O; D9 l, Z# Z C0 j- S 对应 u n 和 u n - 1 ,定义两个迭代变量 y 和 x ,可将上面的递推公式转换成如下迭代关系: 8 j9 h* N h" c- m
& ]9 i7 a. b7 G" r; L4 c7 a4 {$ u xi=gi(X) (I=0,1,…,n-1) " L* ~3 z4 W8 b0 v0 c 1 p. b b: u$ w4 k0 X0 F; u- c 则求方程组根的迭代算法可描述如下: - I( p5 b# ^% A# Q
# m2 |: e) q3 p A) k& ]- u6 H 【算法】迭代法求方程组的根 0 E i @ z, r' {# K5 g2 t% t6 P+ |7 O0 [
{ for (i=0;i 4 o/ z5 M+ e; l I. m% S9 A, |! w * {( Q! G% p# R. K6 ? x=初始近似根; 5 u2 m$ o% ?0 J t% K* b) ^! R* l6 x1 c3 I' p) u* k
do { + c. Z B: r5 j3 v9 i; Y* t , k0 d! O8 A' V' ?- o for (i=0;i 2 K) T2 I$ R' p" E" y- g5 D0 F4 \
9 U1 g( U/ b* s9 i+ a! ^& c y=x; $ l; b5 a/ y, T z- c
& x. Q1 I4 h! \4 U. X for (i=0;i ! U- ]% t0 H- z" x5 ^! f ; D/ W) u. E/ X2 o' I: v x=gi(X); 4 N6 ` ^, H4 Y& ]
" t& w; N9 \/ H. w- @, [
for (delta=0.0,i=0;i 1 _4 r' D; h# {+ y, m* M4 ~ ( c: i: C% f3 K) p, g0 f a if (fabs(y-x)>delta) delta=fabs(y-x); ; D8 R9 M# @+ D
; I* C1 A( M' e. F P5 v } while (delta>Epsilon); + C. X' r0 _, G2 S9 D9 ^2 U1 q- z
/ J+ G H+ b) l# x2 X/ F' j! I2 S' ?# M
for (i=0;i * \ I1 o* k4 R# v1 v
7 {: g3 f: q. z1 X3 [* z+ X
printf(“变量x[%d]的近似根是 %f”,I,x); I2 o0 T+ A( s7 s0 W
: p8 d! a8 l. p7 m
printf(“\n”); ; Z8 P! f# A6 }- j - [2 v+ c; F" A" K+ Y } , m E2 b& E4 F
8 {+ f- U3 \8 |( P% M( M! N
具体使用迭代法求根时应注意以下两种可能发生的情况: # S8 k( o1 X' w; J7 G* M
: n* `: c. F0 p+ {2 E' Y+ p (1) 如果方程无解,算法求出的近似根序列就不会收敛,迭代过程会变成死循环,因此在使用迭代算法前应先考察方程是否有解,并在程序中对迭代的次数给予限制; 5 D0 j' Z4 n4 s+ k9 @ . z/ ^* I6 H$ O* \ (2) 方程虽然有解,但迭代公式选择不当,或迭代的初始近似根选择不合理,也会导致迭代失败。 / h2 c O0 f/ x5 p# m; j/ I . W2 a8 K8 Y! D% z, A 递归 ) ]& [ v! A: ~6 J; g8 | 5 r% [$ a7 T; Q {. X 递归是设计和描述算法的一种有力的工具,由于它在复杂算法的描述中被经常采用,为此在进一步介绍其他算法设计方法之前先讨论它。 ( g) J. f4 M( b% M' |7 G/ s
# H: C; X' M; X9 `7 a" P
能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。 ! G6 I1 c+ S2 h; Y9 w% F2 Z
- L) e0 @) E' O5 ]8 r
【问题】 编写计算斐波那契(Fibonacci)数列的第n项函数fib(n)。 , r: y' x, n# r4 h0 ]
& d5 u e8 n/ x: `" Q4 P
斐波那契数列为:0、1、1、2、3、……,即: ' c( B& x2 _4 ^- W
- N' L- {! u) V5 K3 e/ R+ O- c( A- x
fib(0)=0; ) u M% I( q( v0 f. w. v7 {5 D
" z- L( M1 I& F' g/ I: n$ J+ [( E fib(1)=1; & @" P1 W0 B1 w4 z) I, ~, ]) K) c" F7 @1 {5 a' S
fib(n)=fib(n-1)+fib(n-2) (当n>1时)。 5 [$ c* T# ~* B% g3 |% s1 ^( @! A* x5 C
写成递归函数有: : P0 `& c. m, m. ?$ ]2 d- }8 h; N9 b; ^/ B& W! H( x3 A5 u! P: F
int fib(int n) # B; P9 y/ N/ t; J6 K7 P y. R k0 ?- [: J2 b4 T o
{ if (n==0) return 0; & Z+ ~7 _) L) `$ j$ M
8 Y, }5 u+ h' Y4 r+ w- ?6 M
if (n==1) return 1; ! e; E% ~1 G/ K( L; M8 I4 M/ y
, D$ L8 z1 y# Z' O7 P& ? if (n>1) return fib(n-1)+fib(n-2); S7 s. q+ V n; n9 ^* Y& Y4 z$ @5 N6 G+ E0 X0 o# x! o
} 5 _, c. I& L6 `9 {+ p) b v4 e
( E9 _. o6 h. i- u
递归算法的执行过程分递推和回归两个阶段。在递推阶段,把较复杂的问题(规模为n)的求解推到比原问题简单一些的问题(规模小于n)的求解。例如上例中,求解fib(n),把它推到求解fib(n-1)和fib(n-2)。也就是说,为计算fib(n),必须先计算fib(n-1)和fib(n- 2),而计算fib(n-1)和fib(n-2),又必须先计算fib(n-3)和fib(n-4)。依次类推,直至计算fib(1)和fib(0),分别能立即得到结果1和0。在递推阶段,必须要有终止递归的情况。例如在函数fib中,当n为1和0的情况。 d8 M/ A( B- Q
9 s/ }8 X" ~) s 在回归阶段,当获得最简单情况的解后,逐级返回,依次得到稍复杂问题的解,例如得到fib(1)和fib(0)后,返回得到fib(2)的结果,……,在得到了fib(n-1)和fib(n-2)的结果后,返回得到fib(n)的结果。 # P9 {- N% N; j' Q2 e- [. @8 C5 f% g% ]9 h: j$ S
在编写递归函数时要注意,函数中的局部变量和参数知识局限于当前调用层,当递推进入“简单问题”层时,原来层次上的参数和局部变量便被隐蔽起来。在一系列“简单问题”层,它们各有自己的参数和局部变量。 9 I* o3 a0 o. y4 E8 z$ X4 h
- w% V T5 @) V. h2 V `
由于递归引起一系列的函数调用,并且可能会有一系列的重复计算,递归算法的执行效率相对较低。当某个递归算法能较方便地转换成递推算法时,通常按递推算法编写程序。例如上例计算斐波那契数列的第n项的函数fib(n)应采用递推算法,即从斐波那契数列的前两项出发,逐次由前两项计算出下一项,直至计算出要求的第n项。 ( |4 c4 y* q8 Q% t
$ ^/ ~& b$ U E4 c9 K8 p 【问题】 组合问题 7 @, H/ _5 K, A+ m! n# f$ T9 h6 G9 L
问题描述:找出从自然数1、2、……、n中任取r个数的所有组合。例如n=5,r=3的所有组合为: (1)5、4、3 (2)5、4、2 (3)5、4、1 & j4 ^1 _' P2 y; e# O 2 ^( F" u9 ^ W; v: G (4)5、3、2 (5)5、3、1 (6)5、2、1 : x1 T+ a, o! j Z
& F" z5 y: f' A, p2 J (7)4、3、2 (8)4、3、1 (9)4、2、1 7 `/ C( c! U- B1 n/ u# p* k8 x
9 V" L7 b7 ]. q$ `) d2 H (10)3、2、1 7 ` q; }1 Q* ]/ ^/ }3 D0 f5 l! V
分析所列的10个组合,可以采用这样的递归思想来考虑求组合函数的算法。设函数为void comb(int m,int k)为找出从自然数1、2、……、m中任取k个数的所有组合。当组合的第一个数字选定时,其后的数字是从余下的m-1个数中取k-1数的组合。这就将求m 个数中取k个数的组合问题转化成求m-1个数中取k-1个数的组合问题。设函数引入工作数组a[ ]存放求出的组合的数字,约定函数将确定的k个数字组合的第一个数字放在a[k]中,当一个组合求出后,才将a[ ]中的一个组合输出。第一个数可以是m、m-1、……、k,函数将确定组合的第一个数字放入数组后,有两种可能的选择,因还未去顶组合的其余元素,继续递归去确定;或因已确定了组合的全部元素,输出这个组合。细节见以下程序中的函数comb。 0 U1 w+ ~7 ?1 T6 V0 x2 l. j" Z' A
, W) }1 j% a" W1 h0 I0 P( S' G
【程序】 8 T0 Q* i3 q: m# t/ A. _
4 J' k* S$ h. U6 i8 g4 V1 U
# include $ c) C. \8 X+ ~9 S7 U/ t. E ; E2 K' W. E: s- _0 } # define MAXN 100 7 H y) N3 x/ b; I9 h9 @, ^( d) A( e9 T9 i" u( m
int a[MAXN]; 3 B3 N; g$ [8 o1 [9 D0 }. Y7 h
: g$ C# r9 H* f0 n% \( U" ]7 U void comb(int m,int k) 3 B( G5 d# S# q/ p, O Z * I1 _/ _' [8 v# `+ F { int i,j; & B! _" \( o W. L* l/ `
# T1 M( A* R. P$ D2 O& ?; ? for (i=m;i>=k;i--) - n, j! E$ w* @+ e* n& A( f N0 A0 J$ J9 i+ u. G; \, U4 l/ Q
{ a[k]=i; / u, F8 d+ m# x4 R" C* y$ g
. _' @9 q% t' d
if (k>1) 3 N2 H- z) c1 H3 d* x& ^! ~
* O- o) l* L6 T2 d; T comb(i-1,k-1); 1 I) r* f6 p- g/ \6 V) ~ j
3 X# X3 E1 m) b
else + W @2 Z j, Z- ~/ d7 w- o$ `8 O, M5 y/ B( F( v
{ for (j=a[0];j>0;j--) # k2 B" _9 b- ` . o. E! T" l% [% d1 q; _# @) T printf(“%4d”,a[j]); 4 i& @0 D5 {& ?3 n% T
# X, ~. \% P- W/ D6 E% A# H
printf(“\n”); 8 G5 B2 r# ^1 Z 9 o6 H% s# G1 o( W) N; w } 3 [% y/ n( ]) z! C; j/ n
. v% ]1 d: x* s* E
} 3 r; R: V- w4 ?" ]% w
, z8 }& C- C- B# F! K } # Z/ p: l! i+ U! U( N2 P4 W; X6 e$ V/ X! o, D; _. C, K$ B6 N
void main() * @" y* q7 h. o+ p+ h8 \ 9 K- a/ s. x- P9 ~- M% V { a[0]=3; 2 y0 ^1 c/ M: b9 R: l
+ z3 G7 _; e4 F& z" ?9 R
comb(5,3); # }+ n1 S# s! ] 1 n% _, n7 [" f. y3 A } ( z* j% B7 [* N* W) \ 6 l3 u5 ?0 j; g! G# f 【问题】 背包问题 3 ]# B$ C! }' e" p
5 H* F6 n5 z5 X! P. s
问题描述:有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物品的选择方案,使选中物品的总重量不超过指定的限制重量,但选中物品的价值之和最大。 $ g' Z q2 F2 Y0 {) c ( f( a$ L# z _& M0 A 设n 件物品的重量分别为w0、w1、…、wn-1,物品的价值分别为v0、v1、…、vn-1。采用递归寻找物品的选择方案。设前面已有了多种选择的方案,并保留了其中总价值最大的方案于数组option[ ],该方案的总价值存于变量maxv。当前正在考察新方案,其物品选择情况保存于数组cop[ ]。假定当前方案已考虑了前i-1件物品,现在要考虑第i件物品;当前方案已包含的物品的重量之和为tw;至此,若其余物品都选择是可能的话,本方案能达到的总价值的期望值为tv。算法引入tv是当一旦当前方案的总价值的期望值也小于前面方案的总价值maxv时,继续考察当前方案变成无意义的工作,应终止当前方案,立即去考察下一个方案。因为当方案的总价值不比maxv大时,该方案不会被再考察,这同时保证函数后找到的方案一定会比前面的方案更好。 + _* c0 t. T0 l8 P2 n9 ~ % B$ u }6 `* N$ p9 W 对于第i件物品的选择考虑有两种可能: x' n6 ~; D. a7 G. y e5 J" B' ~3 K0 E3 i5 O* z& d
(1) 考虑物品i被选择,这种可能性仅当包含它不会超过方案总重量限制时才是可行的。选中后,继续递归去考虑其余物品的选择。 ! ^! {8 n6 F: T$ W$ E9 K/ Q & Z$ V& K1 |! K0 ]7 ^ (2) 考虑物品i不被选择,这种可能性仅当不包含物品i也有可能会找到价值更大的方案的情况。 ) o5 ]$ u- P. y4 E3 D" ~* ]% ?6 H5 `5 k
按以上思想写出递归算法如下: + r; t! ^% O' Z& g) j$ x
7 o* a% ]3 [# l" Z1 ?8 n try(物品i,当前选择已达到的重量和,本方案可能达到的总价值tv) 8 H0 X1 T* O6 f' m7 R) d" }+ H8 d& G; `) O- V0 M
{ /*考虑物品i包含在当前方案中的可能性*/ 1 Y1 L9 c& d C; `& w5 ]& p+ |$ W8 \
if(包含物品i是可以接受的) ' _- o; }, y% T) Y, |3 z1 l Z
) \+ ^/ I! A: _- g; ^
{ 将物品i包含在当前方案中; 4 Z# t+ i5 l% S9 K* n3 B4 S( A: M! z7 T
if (i # N2 }, @. [0 ^; m; h- G3 Q; { 5 A, z" E1 Q8 g, ~5 q9 } try(i+1,tw+物品i的重量,tv); + z+ v6 W8 y. y& ?% h/ b# K' | 7 @& e9 W& X. |6 ^* o else - N- w3 v9 C% s# z7 V& t" e . H/ L$ d* s0 o L& L /*又一个完整方案,因为它比前面的方案好,以它作为最佳方案*/ " |4 F! [% o6 [% H+ \- d8 H* J- {5 h, T
以当前方案作为临时最佳方案保存; 1 R9 k# W* }9 p6 P8 A
' E) e8 X( t: ?% z4 U w
恢复物品i不包含状态; - n4 d) ^$ J! C5 _6 ~" ?
5 e" X3 g- m7 z9 T
} 6 i2 d1 V$ c/ j. J & _1 ?3 G( h0 u7 e0 D; r /*考虑物品i不包含在当前方案中的可能性*/ 3 Y3 o: G7 j! J; J8 P2 @2 ?
9 Z* S5 z% `" H" }$ o7 X if (不包含物品i仅是可男考虑的) ! ?, u" p# [7 W0 d& j- o
2 n4 P& D% u0 R5 S# X2 `" Z if (i ; O8 l3 ~; p/ n: }) y
; l2 R5 y8 p; x: F' ~! o
try(i+1,tw,tv-物品i的价值); % a' e. i* X; n. j) W( b" s) c 5 Q2 r2 i5 j+ D- W- p/ V4 H9 i else ' q/ {- K; _# |6 @( g7 r8 q ! i7 f. F c6 R% G$ W% F /*又一个完整方案,因它比前面的方案好,以它作为最佳方案*/ ; B' s! E, p( D, A3 @8 S! J* w. f% P& O: d
以当前方案作为临时最佳方案保存; + j2 J; Q# W- {0 V- o' n" }$ B1 a% _* M7 O; m ) Q) `# Z" k, e } 0 u$ O% Z( e2 t) d; O) h7 _- B
! p& c4 Q, t# S" F
为了理解上述算法,特举以下实例。设有4件物品,它们的重量和价值见表: 0 u! G! s( T/ G: `' V6 P
% y, I! k/ ]! C! t3 z( D+ o
物品 0 1 2 3 4 S5 b7 B- i$ ^0 \' Z+ A, T1 q- ^8 N# `
重量 5 3 2 1 ; D3 `: t x) M8 |; I5 ]
+ f* f: f% j M G$ } H
价值 4 4 3 1 + p: E9 V6 w5 L: Q: r* j ) i/ z( Q: s7 m( L; h+ S0 C4 X2 x4 [ 并设限制重量为7。则按以上算法,下图表示找解过程。由图知,一旦找到一个解,算法就进一步找更好的佳。如能判定某个查找分支不会找到更好的解,算法不会在该分支继续查找,而是立即终止该分支,并去考察下一个分支。 ) v; h4 j/ a6 q/ t3 s' n, A
' q3 v8 ]( @: S2 u- c
按上述算法编写函数和程序如下: ( ?9 Y+ w2 _) ^: `; b: J 2 {3 F$ C! c; |- @/ f: `9 f 【程序】 " R4 ?" ]2 G% n) k$ M
' x/ j- S) _$ ?/ m8 ` # include 0 p; X8 }" C7 m* J& }* A
, S6 q8 W/ F9 [6 S. ` # define N 100 * q* P2 @ G; Q: f) z
! o0 d$ Q& [) G) l
double limitW,totV,maxV; 9 ]8 c0 v O3 D4 b; }3 O" \, j9 X4 q9 S6 V
int option[N],cop[N]; - O1 k0 \! C( Q6 K/ L6 s9 g" Z% o
/ z8 G( D. z% O) K0 @
struct { double weight; ' [( P- O3 C, u/ @. N' F6 x
% Y- e$ V+ ]% d, l- ]! L$ c
double value; " ?1 G1 K, B+ F 7 d4 @7 r' [ ` W6 h, E" g D }a[N]; 6 m& O" Y' E! X: ^; }5 s" E n9 X7 c( E0 ?* Y3 Z, i2 E5 I
int n; * C( q) x$ r0 ^& f! j. e/ t( W' W3 G( H L8 q
void find(int i,double tw,double tv) ' }" S" z$ H) G& q
N) w: t0 v: d: H
{ int k; ( X6 V( Z0 Y ]0 L) u: L
' t! k- Q4 M9 B; S9 D5 k /*考虑物品i包含在当前方案中的可能性*/ ( i: F% F0 v& }& S
8 W" r3 Z8 U: c; q if (tw+a.weight<=limitW) 1 V- C* K( I! [ ~( z& t. E
- {1 \ ~, _) b0 K
{ cop=1; 9 p8 m3 u9 M+ C$ R+ L/ {; k
) {8 E% W" b. z/ [
if (i E0 E& B& V3 f* J) @/ @5 G' U! j# w; Y( J; D( u' r) P9 `( ]: s
else ; v' |( j+ w5 ~4 J N1 u0 F
9 Y7 f: i2 [, i& q3 S+ d* {
{ for (k=0;k , t: d1 L0 V: `# V; H 8 F( O; _0 \( a; S1 }7 ] option[k]=cop[k]; ! c" {, x) Y. ]/ o, a9 ~1 S9 D6 u+ V; c( h2 @* \" e% P5 x# N
maxv=tv; ( U6 C4 a( g0 P t) Q
, M+ T5 a/ b& c2 _ } + ~' { P. A% P) P2 A, ^- S 3 i4 [% S- J0 a* f cop=0; ( |. N! }0 U$ z' o5 H ! c: {/ _% D- i/ u1 b8 k } ( a. s- c% |6 ^- a& D* p( K9 \
6 M% Q- K; P) l, X
/*考虑物品i不包含在当前方案中的可能性*/ 5 q- `4 y+ z. K/ E( R9 Y* m5 ?
8 K3 Y0 q4 o' \ h
if (tv-a.value>maxV) : c5 X" o% J- G% _5 V% p% H: S" H& C" c$ ] v* D" x. h
if (i % a* R2 o4 X0 t9 M; s9 a9 g' n- e5 k! V& H( Q9 V" j3 c
else t2 h$ w! s! p" t" O. \
: |9 q4 @$ ~5 X! |6 Z/ ` { for (k=0;k 2 s z( ]5 k! o; ^" ]5 e
) e1 h* x% A; j) F" S
option[k]=cop[k]; / X D1 ?; \. t7 {: k0 N9 F7 I* p/ u" ?' W. r
maxv=tv-a.value; . N: k. g: q& [0 W- L& H0 ^6 X$ `4 o& G; @ Q
} 6 F% b0 R9 u9 r- g, O0 E7 w + t. I& @0 ^% c* ~ } - H* u, P' A1 @3 u0 V1 ?
' a# R% u* l: m6 H. i( c
void main() & | x& b0 p* U% M6 O6 c( {# R6 D: f; |5 t& H8 Z
{ int k; , K6 {1 q4 ]/ O4 W
/ q z9 h9 n7 S3 L4 n# G double w,v; 2 o3 C3 m# z& G+ d: C
% ~& r! R; N2 \
printf(“输入物品种数\n”); + H3 L* d% E) ~4 i3 ?, E R1 c" Z
* w/ @1 L2 \' ~4 K5 X X5 h scanf((“%d”,&n); ! X& e2 B0 S& q: n ! p9 @% n$ B1 @% L# J printf(“输入各物品的重量和价值\n”); # W0 f8 N+ o) ]/ P
; x9 ^$ y, y8 w2 F) x9 D
for (totv=0.0,k=0;k $ c! A4 Y" r/ m7 c1 A
: Q7 X4 x3 \( i3 M { scanf(“%1f%1f”,&w,&v); 7 F+ @% I( Z5 D# S/ T i# ^. K- E( m7 X* X a! _! H3 R
a[k].weight=w; " f/ v* V$ {7 h/ ?. v( D; v" d " L9 _) X& d9 ]5 p; I9 N a[k].value=v; 4 `& j& x2 a- P5 f' U0 W4 m s* Q+ p$ ^; [# S
totV+=V; , i. q7 C9 t7 W, `( U2 | 4 L% k2 ~3 T, a) D0 P } ( p. {% h$ Q* Q! R' x0 O
2 H9 K+ D! b3 e3 L6 j# O printf(“输入限制重量\n”); 3 d+ U5 Y2 }- F0 D# o2 y2 p 6 ?4 [9 U+ F. M scanf(“%1f”,&limitV); 8 G3 r& p. s+ t j
/ s2 b' V6 a( R! U' D0 d maxv=0.0; # H* s8 U4 c# q) Y0 W
1 y8 H& G5 E0 u8 n h; u2 o' @- }
for (k=0;k find(0,0.0,totV); 4 y, k2 s, Y8 S5 F
9 k( [2 v0 X8 p( `7 O for (k=0;k 9 P' D7 z x9 H. ? j0 O( e2 G5 e2 I/ ~. _0 w
if (option[k]) printf(“%4d”,k+1); 6 W5 y0 o* x! h8 l& L1 o4 T2 ?, \4 p* f4 t4 J$ V
printf(“\n总价值为%.2f\n”,maxv); ' I' I+ g0 B$ X) y- O
; l* d1 C' m' A' Y( M } 2 N% Z0 b$ v0 }" ^8 s0 r+ G: W- k, {% ~* W
作为对比,下面以同样的解题思想,考虑非递归的程序解。为了提高找解速度,程序不是简单地逐一生成所有候选解,而是从每个物品对候选解的影响来形成值得进一步考虑的候选解,一个候选解是通过依次考察每个物品形成的。对物品i的考察有这样几种情况:当该物品被包含在候选解中依旧满足解的总重量的限制,该物品被包含在候选解中是应该继续考虑的;反之,该物品不应该包括在当前正在形成的候选解中。同样地,仅当物品不被包括在候选解中,还是有可能找到比目前临时最佳解更好的候选解时,才去考虑该物品不被包括在候选解中;反之,该物品不包括在当前候选解中的方案也不应继续考虑。对于任一值得继续考虑的方案,程序就去进一步考虑下一个物品。 6 x x% q- b' `& k8 Y; ]" M6 k. i8 ~2 O% j
【程序】 ; N" q/ t$ ~! A: r% [ 4 N' N4 n* {# C, a # include - H, e% _/ A% w0 t7 `7 x$ A: o( z- `1 Z" r/ o4 ^
# define N 100 " Z4 Y+ ]4 p! ^3 U- j+ {3 I! v+ h( l& L" _# M
double limitW; ; X, D6 ~( s! m; X0 r1 {9 O 4 R( b6 j9 L) _/ N* A int cop[N]; * n# {7 G$ a0 a2 J( O; k: P' C6 R$ d 7 C+ e3 R/ c. F0 H struct ele { double weight; " n" u; m( N; }) M2 w! v& E
$ A+ P4 `# |4 t! e+ J; W9 {7 [% `0 @ double value; $ _ w6 p' n' z3 K 5 `- A( E% m# e$ `5 @2 h. O+ @$ O" X% R } a[N]; 6 b7 G+ k I% d! l, H; N 6 g$ f) N( Y4 v1 w* R M% M int k,n; + o, A! r% U3 }8 s' M2 ^- `7 Z" G% O; K4 z6 Y/ p% N! I
struct { int ; 1 @. E! _+ v7 `
5 a# u% n5 z1 G- W1 u
double tw; 9 Q9 s L# l! ? , \# {$ R4 @$ v+ W# r# U/ `; B- @ double tv; 2 O. L. ?% L% c/ x: \4 T- C8 L' M5 e 5 m( R) @, Z4 Q- l }twv[N]; ) k+ R# y4 F" {/ H
- a4 l& V6 `/ ` W; L. _
void next(int i,double tw,double tv) * H6 u, a0 a8 H R& z2 N+ G, t2 @ { twv.=1; 6 q1 J4 D/ \) R* Y: w6 R2 G; c' Y: o& {1 W
twv.tw=tw; ) O9 D- X- d5 g0 r( ]3 O: P. a, a; A! }. D3 B4 j$ q
twv.tv=tv; ) d7 D+ k5 G0 Y) R; a# Y# h& d( u
( p+ V! R; N6 R } / K, C. Z& |, B$ x2 S: W& i" z2 _
2 |2 x2 g7 V6 F double find(struct ele *a,int n) # ^* q9 B6 c3 L/ h! s ; k/ N( U# K# B# Z7 d { int i,k,f; " s, ^) Y9 M- e9 _8 N* R + ?2 g; q Y8 x q3 J4 U double maxv,tw,tv,totv; , T. s/ n4 p) w! ?( ]
( u# A1 y. W! S! o; ^, f0 f& Y
maxv=0; / D( _7 l, c, z: W; B, K; j# ~
( z+ j' }/ ?. g
for (totv=0.0,k=0;k 3 Z$ p5 y- o' h' E7 F& L9 R/ c. h! [! S" Y9 C
totv+=a[k].value; ' w. q: N( W! B p
3 \" u! I$ k5 i9 G" f" I' E% V- B next(0,0.0,totv); ( ]! N0 j1 _/ u7 H6 ?5 r
$ o" C7 @' A$ O6 \
i=0; . g* m }' c# k0 a! |" p# D0 o! t; {& Q3 f% X" e
While (i>=0) ( ?# Y* J# U# ?" t) `$ p" z, u. Q6 W
( a$ |) E8 o0 U l
{ f=twv.; , ?0 r( @. R: L8 ]2 B; N- B+ h B) x" N( `! s7 \
tw=twv.tw; & W* |1 w9 g- j
+ i5 K% H, y) g
tv=twv.tv; 0 [, C6 Z3 v) F" \) k# K; O) v* J3 d+ v, A: r
switch(f) 7 q3 Z1 {( N* t3 a: j+ Z. c: x; _