二、穷举搜索法 i.]}ooI
l d@^$
穷举搜索法是对可能是解的众多候选解按某种顺序进行逐一枚举和检验,并从众找出那些符合要求的候选解作为问题的解。 l #Tm`br
【问题】 将A、B、C、D、E、F这六个变量排成如图所示的三角形,这六个变量分别取[1,6]上的整数,且均不相同。求使三角形三条边上的变量之和相等的全部解。如图就是一个解。 r]yq
#T`z
程序引入变量a、b、c、d、e、f,并让它们分别顺序取1至6的证书,在它们互不相同的条件下,测试由它们排成的如图所示的三角形三条边上的变量之和是否相等,如相等即为一种满足要求的排列,把它们输出。当这些变量取尽所有的组合后,程序就可得到全部可能的解。细节见下面的程序。 ,^(T^ -
【程序1】 3y!CkJKv
# include <stdio.h> YY9q'x,w
void main() TFhj]r^{
{ int a,b,c,d,e,f; UTz;Sw?~hw
for (a=1;a<=6;a++) DRnXo-Aaj
for (b=1;b<=6;b++) { -p1arA
if (b==a) continue; `@90b4u
for (c=1;c<=6;c++) { oj/tim
if (c==a)||(c==b) continue; 7hc(]8eP
for (d=1;d<=6;d++) { BBDOjhik
if (d==a)||(d==b)||(d==c) continue; `u-}E9{
for (e=1;e<=6;e++) { n\ZFPXP
if (e==a)||(e==b)||(e==c)||(e==d) continue; 5"sF#Y&
f=21-(a+b+c+d+e); Q'N<jX[
if ((a+b+c==c+d+e))&&(a+b+c==e+f+a)) { j(SQNSFD
printf(“%6d,a); _i&\G}mrC
printf(“%4d%4d”,b,f); mnePm{
printf(“%2d%4d%4d”,c,d,e); (?Yz#Yf
scanf(“%*c”); LTF%bAQ,
} >/>a++19
} hN.#ui5 $
} aCanDMcBnq
} /[IK[
} P_;oSN|>
} )gR&Ms4
按穷举法编写的程序通常不能适应变化的情况。如问题改成有9个变量排成三角形,每条边有4个变量的情况,程序的循环重数就要相应改变。 nD_g84us
对一组数穷尽所有排列,还有更直接的方法。将一个排列看作一个长整数,则所有排列对应着一组整数。将这组整数按从小到大的顺序排列排成一个整数,从对应最小的整数开始。按数列的递增顺序逐一列举每个排列对应的每个整数,这能更有效地完成排列的穷举。从一个排列找出对应数列的下一个排列可在当前排列的基础上作部分调整来实现。倘若当前排列为1,2,4,6,5,3,并令其对应的长整数为124653。要寻找比长整数124653更大的排列,可从该排列的最后一个数字顺序向前逐位考察,当发现排列中的某个数字比它前一个数字大时,如本例中的6比它的前一位数字4大,这说明还有对应更大整数的排列。但为了顺序从小到大列举出所有的排列,不能立即调整得太大,如本例中将数字6与数字4交换得到的排列126453就不是排列124653的下一个排列。为了得到排列124653的下一个排列,应从已经考察过的那部分数字中选出比数字大,但又是它们中最小的那一个数字,比如数字5,与数字4交换。该数字也是从后向前考察过程中第一个比4大的数字。5与4交换后,得到排列125643。在前面数字1,2,5固定的情况下,还应选择对应最小整数的那个排列,为此还需将后面那部分数字的排列顺序颠倒,如将数字6,4,3的排列顺序颠倒,得到排列1,2,5,3,4,6,这才是排列1,2,4,6,5,3的下一个排列。按以上想法编写的程序如下。 E-/]UH3u H
【程序2】 ;RrfE8mGj
# include <stdio.h> q&+GpR
# define SIDE_N 3 6*e:ey U
# define LENGTH 3 *?uF&( 0
# define VARIABLES 6 E,;nx^`!l
int A,B,C,D,E,F; |^=`ln!
int *pt[]={&A,&B,&C,&D,&E,&F}; a'|0e]
int *side[SIDE_N][LENGTH]={&A,&B,&C,&C,&D,&E,&E,&F,&A}; k;)L-ge9
int side_total[SIDE_N]; \ l:n
main{} ,UP6.C14
{ int i,j,t,equal; R'{V&H^Z
for (j=0;j<VARIABLES;j++) :+YFO.7
*pt[j]=j+1; lfhB2^^
while(1) ZE :oK
{ for (i=0;i<SIDE_N;i++) ?vhW`LXNB
{ for (t=j=0;j<LENGTH;j++) rScmUt
t+=*side[j]; au8)G_A
side_total=t; {BJxRH"&6*
} ELm#
for (equal=1,i=0;equal&&i<SIDE_N-1;i++) hZpFI?lqc\
if (side_total!=side_total[i+1] equal=0; }>j$Wr_h
if (equal) Bg3^BOT
{ for (i=1;i<VARIABLES;i++) @=9QV3D
printf(“%4d”,*pt); Nb$ )YMbA
printf(“\n”); `1P
&
scanf(“%*c”); WN0^hDc-
} 0ul2rZc
for (j=VARIABLES-1;j>0;j--) Pvtf_Qo^
if (*pt[j]>*pt[j-1]) break; jj^CW"IB
if (j==0) break; Q|0[B4e^:
for (i=VARIABLES-1;i>=j;i--) m\t
%wr
if (*pt>*pt[i-1]) break; YrdK@I
t=*pt[j-1];* pt[j-1] =* pt; *pt=t; 1.uyu
for (i=VARIABLES-1;i>j;i--,j++) +n0y/0Au
{ t=*pt[j]; *pt[j] =* pt; *pt=t; } SZgH0W("L
} ]t,ppFC#
} NZl0sX.:
从上述问题解决的方法中,最重要的因素就是确定某种方法来确定所有的候选解。下面再用一个示例来加以说明。 ur'A ;B
【问题】 背包问题 V7&