pascal搜索回溯.docx

上传人:b****4 文档编号:11535282 上传时间:2023-03-19 格式:DOCX 页数:16 大小:25.79KB
下载 相关 举报
pascal搜索回溯.docx_第1页
第1页 / 共16页
pascal搜索回溯.docx_第2页
第2页 / 共16页
pascal搜索回溯.docx_第3页
第3页 / 共16页
pascal搜索回溯.docx_第4页
第4页 / 共16页
pascal搜索回溯.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

pascal搜索回溯.docx

《pascal搜索回溯.docx》由会员分享,可在线阅读,更多相关《pascal搜索回溯.docx(16页珍藏版)》请在冰豆网上搜索。

pascal搜索回溯.docx

pascal搜索回溯

【题目】求集合元素问题(1,2x+1,3X+1类)

某集合A中的元素有以下特征:

(1)数1是A中的元素

(2)如果X是A中的元素,则2x+1,3x+1也是A中的元素

(3)除了条件

(1),

(2)以外的所有元素均不是A中的元素

[参考程序1]

usescrt,dos;

vara:

array[1..10000]oflongint;

b:

array[1..10000]ofboolean;

times,n,m,long,i:

longint;

hour1,minute1,second1,sec1001:

word;

hour2,minute2,second2,sec1002:

word;

begin

write('N=');readln(n);

{gettime(hour1,minute1,second1,sec1001);

times:

=minute1*60+second1;

writeln(minute1,':

',second1);}

fillchar(b,sizeof(b),0);

a[1]:

=1;m:

=2;long:

=1;

whilelong<=ndobegin

fori:

=1tolongdo

if(a[i]*2=m-1)or(a[i]*3=m-1)then

ifnotb[m]thenbegin

inc(long);a[long]:

=m;b[m]:

=true;break;

end;

inc(m);

end;

{gettime(hour2,minute2,second2,sec1002);

times:

=minute2*60+second2-times;

writeln(minute2,':

',second2);

writeln('Ok!

UsesTime:

',times);}

fori:

=1tondowrite(a[i],'');

readln;

end.

[参考程序2]

usescrt;

constn=10000;

vara:

array[1..n]oflongint;

i,j,k,l,y:

longint;

begin

clrscr;

fillchar(a,sizeof(a),0);

i:

=1;j:

=1;

a[i]:

=1;

repeat

y:

=2*a[i]+1;

k:

=j;

whiley〈a[k]dobegin

a[k+1]:

=a[k];

k:

=k-1;

end;

ify>a[k]thenbegin

a[k+1]:

=y;j:

=j+1;

end

elseforl:

=k+1tojdoa[l]:

=a[l+1];

j:

=j+1;

a[j]:

=3*a[i]+1;

inc(i);

untilk>=n;

fori:

=1tondobegin

write(a[i],'');

if(imod10=0)or(i=n)thenwriteln

end;

end.

[参考程序3]

usescrt;

vara:

array[1..10000]oflongint;

n,i,one,another,long,s,x,y:

longint;

begin

write('n=');readln(n);

a[1]:

=1;long:

=1;one:

=1;another:

=1;

whilelongythenbegins:

=y;inc(another);end

elsebegins:

=x;inc(one);inc(another);end;

inc(long);a[long]:

=s;

end;

fori:

=1tondowrite(a[i],'');

end.

[参考程序4]

varn:

integer;

top,x:

longint;

functioninit(x:

longint):

boolean;

begin

ifx=1theninit:

=true

elseif((x-1)mod2=0)and(init((x-1)div2))

or((x-1)mod3=0)and(init((x-1)div3))then

init:

=true

elseinit:

=false;

end;

begin

write('inputn:

');

readln(n);

x:

=0;

top:

=0;

whiletop

x:

=x+1;

ifinit(x)then

top:

=top+1;

write(x:

8);

end;

write('outputend.');

readln

end.

〖问题描述〗用高精度计算出S=1!

+2!

+3!

+...n!

(n<=50)

其中"!

"表示阶乘,例如:

5!

=5*4*3*2*1

要求:

输入正整数N,输出计算结果S

            四、搜索回溯法

搜索回溯法是程序设计中最常用的一种算法,其思想方法是按一定的顺序对每阶段试探所有可能性:

即从初始态出发向前搜索,如果成功则继续,否则回退一步,如此反复直至所有可能都试遍。

在搜索过程中,须作标志以记住已搜索过的步骤,设栈实现回溯。

算法框架

  1、初始化

  2、进行第一步搜索(试探)

  3、判断搜索是否成功,若成功转5;若不成功,则继续

  4、进行该步下一种情况搜索,若该步所有可能都搜索完则转8;否则转3

  5、当前情况步数等作标志(进栈),并前进一步

  6、判断是否搜索到终点,不是则转2;否则继续。

  7、打印结果,清除并转4

  8、退后一步(回溯)

  9、判断是否退回到初始态,不是则转4;是则结果程序

一、素数环把从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。

〖算法分析〗从1开始,每个空位有20(19)种可能,只要填进去的数合法:

与前面的数不相同;与左边相邻的数的和是一个素数。

第20个数还要判断和第1个数的和是否素数。

1、数据初始化;

2、递归填数:

判断第J种可能是否合法;

A、如果合法:

填数;判断是否到达目标(20个已填完):

是,打印结果;不是,递归填下一个;

B、如果不合法:

选择下一种可能;

programtt;

vara:

array[1..20]ofinteger;

k:

integer;

functionpd1(j,i:

integer):

boolean;

begin

pd1:

=true;

fork:

=1toi-1do

ifa[k]=jthenbeginpd1:

=false;exit;end;

end;

functionpd2(x:

integer):

boolean;

begin

pd2:

=true;

fork:

=2totrunc(sqrt(x))do

ifxmodk=0thenbeginpd2:

=false;exit;end;

end;

functionpd3(j,i:

integer):

boolean;

begin

ifi<20thenpd3:

=pd2(j+a[i-1])

elsepd3:

=pd2(j+a[i-1])andpd2(j+1);

end;

procedureprint;

begin

fork:

=1to20dowrite(a[k]:

4);

writeln;

end;

proceduretry(i:

integer);

varj:

integer;

begin

forj:

=2to20do

begin

ifpd1(j,i)andpd3(j,i)thenbegin

a[i]:

=j;

ifi=20thenbeginprint;halt;end

elsetry(i+1);

a[i]:

=0;

end;

end;

end;

begin

fork:

=1to20doa[k]:

=0;

a[1]:

=1;

try

(2);

end.

二、编写程序走左图所示的迷宫,要求从A走到B,并印出路径,在走迷宫的过程中,若遇到死胡同,退出时即给堵上。

〖算法分析〗:

将每一格对应每一步,每走一步计算相应的坐标值,每一步又按1、2、3、4四个方向进行试探,是否有路,若有路则前进,否则换方向继续试探;若四个方向都不行,则回溯,并将此路堵上。

三、八皇后问题在一个8×8的棋盘里放置8个皇后,要求每个皇后两两之间不相"冲"(在每一横列竖列斜列只有一个皇后)。

〖问题分析〗主要解决以下几个问题:

1、冲突。

包括行、列、两条对角线:

(1)列:

规定每一列放一个皇后,不会造成列上的冲突;

(2)行:

当第I行摆上皇后,则同一行上不能再放皇后,把I为下标的标记置为被占领状态;

(3)对角线:

对角线有两个方向。

在同一对角线上的所有点(设下标为(i,j)),要么(i+j)是常数,要么(i-j)是常数。

因此,当第I个皇后占领了第J列后,要同时把以(i+j)、(i-j)为下标的标记置为被占领状态。

2、数据结构。

(1)解数组A。

A[I]表示第I个皇后放置的列;范围:

1..8

(2)行冲突标记数组B。

B[I]=0表示第I行空闲;B[I]=1表示第I行被占领;范围:

1..8

(3)对角线冲突标记数组C、D。

C[I-J]=0表示第(I-J)条对角线空闲;C[I-J]=1表示第(I-J)条对角线被占领;范围:

-7..7

D[I+J]=0表示第(I+J)条对角线空闲;D[I+J]=1表示第(I+J)条对角线被占领;范围:

2..16

〖算法流程〗

1、数据初始化。

2、从n列开始摆放第n个皇后,先测试当前位置(n,m)是否等于0(未被占领):

如果是,摆放第n个皇后,并宣布占领(记得要横列竖列斜列一起来),接着进行递归;

如果不是,测试下一个位置(n,m+1),若当n<=8,m=8时,已经无法摆放时,进行回溯。

3、当n>8时,便一一打印出结果。

皇后N

4

5

6

7

8

9

10

方案数

2

10

4

40

92

352

724

programqueen;{八皇后问题程序}

constn=8;

vara,b:

array[1..n]ofinteger;{数组a存放解:

a[i]表示第i个皇后放在第a[i]列;}

   c:

array[1-n,n-1]ofinteger;

   d:

array[2..n+n]ofinteger;{b为行标志,c、d表示对角线标志}

   k:

integer;

procedureprint;{打印结果}

varj:

integer;

begin

         forj:

=1tondowrite(a[j]:

4);     writeln;

end;

procedruetry(i:

integer);{递归搜索解}

varj:

integer;{每个皇后的可放置位置。

注意:

一定要在过程中定义;否则当递归时会覆盖掉它的值,不能得到正确结果}

begin

    forj:

=1tondo

    begin

         if(b[j]=0)and(c[i-j]=0)and (d[i+j]=0)then{检查位置是否合法}

         begin

            a[i]:

=j;{置第i个皇后的位置是第j行}

            b[j]:

=1;    c[i-j]:

=1;    d[i+j]:

=1;{作已摆放标志}

            ifi

            b[j]:

=0;c[i-j]:

=0;d[i+j]:

=0;{回溯:

清摆放标志}

        end;

     end;

end;

begin

         fork:

=1tondob[k]:

=0;{初始化数据}

         fork:

=1-nton-1doc[k]:

=0;

         fork:

=2ton+ndod[k]:

=0;

         try

(1);

end.

四、〖题目描述〗输入两个数字(i,j),在第一个数字i中间添上若干个加号,使得这个代数式的值等于第二个数字j。

〖问题分析〗这道题采用的算法是剪枝搜索,逐一在第一个数字i各个数字之间添上加号,并计算出当前代数式的值,如果等于第二个数字j,则退出循环,打印结果“YES”;如果不是,则继续循环;当循环结束后,还未能得出第二个数j,则打印结果“NO”。

〖算法流程〗

1、首先将以字符串输入的第一个数字i切成一个数字e段,放进一个数组a[e]里。

2、接着进行循环,逐一在第一个数字i各个数字之间添上加号,由于在各个数字之间添上加号后代数式的值只有两种情况:

大于第二个数字j或小于第二个数字j,所以循环的内容可以如下:

(1)以h,i分别作为当前处理的数字的首位在数组里的位置和在当前数字的第i位添加号。

(2)分别以x1,x2存放添加号后加号前的数值以及加号后的数值,x3将赋值为x1+x2,作为当前代数式的值。

当x3>j时,则进行将h赋值为i,将要处理的数字赋值为加号后的数值,并将x3赋值为x3-x2,作为加号前的数值;当x3e时,则将h赋值为h-1,i赋值为h+1,在当前处理的数字添加号的数位的前一位添上加号,并将x3赋值为x3-x2-a[i]。

3、当h<=0、h>e、i<=0、i>e、x3<>j时,则退出循环并打印结果“no”;当0

〖参考程序〗

programaa;

vara,b:

text;

c:

string;

d,e,g,h,i,x1,x2,x3,xx:

integer;

f:

array[1..100]ofinteger;

procedurebb;

begin

assign(a,'tjh.dat');

reset(a);

readln(a,c,d);

close(a);

end;

procedurecc;

begin

fore:

=1tolength(c)do

f[e]:

=ord(c[e])-48;

x1:

=0;x2:

=0;x3:

=0;xx:

=1;h:

=1;i:

=1;

whilex3<>ddo

begin

forg:

=htoidox1:

=x1*10+f[g];

forg:

=i+1toedox2:

=x2*10+f[g];

x3:

=x1+x2+x3;

ifx3=dthenexit;

if(h<0)or(i<0)thenbeginxx:

=0;exit;end;

ifx3

begin

i:

=i+1;x3:

=x3-x1-x2;

ifi=5thenbeginh:

=h-1;i:

=h+1;x3:

=x3-f[i-1];end;

x1:

=0;x2:

=0;

end;

ifx3>dthen

begin

h:

=h+1;i:

=h;x1:

=0;x3:

=x3-x2;x2:

=0;

end;

end;

end;

proceduredd;

begin

assign(b,'tjh.out');

rewrite(b);

ifxx=1thenwriteln(b,'yes')

elsewriteln(b,'no');

close(b);

end;

begin

bb;

cc;

dd;

end.

〖习题〗

2、骑士游历问题设有一个N*M的棋盘(2≤N≤50,2≤M≤50),如图所示。

在棋盘上任一点有一个中国象棋马,马走的规则:

(1)马走日字;

(2)马只能向右走;问题:

当N,M输入之后,找出一条从左下角到右上角的路径。

如:

输入N=4,M=4。

输出(1,1)-(2,3)-(4,4),若不存在路径,则输出‘NO’。

3、任何大于1的自然数N都可以拆分成若干个小于N的自然数之和。

输入N,计算和输出N的不同拆分方案。

4、有一集合,集合中有N个元素,每个元素都是正整数,它们存放在一维数组中,每个数组元素存放一个数,对给定的整数TOTAL(设集合中的每个元素的值都小于TOTAL),求出所有满足下列条件的子集,子集中各元素之和等于TOTAL。

(如设:

TOTAL=10,N=7,元素8,4,1,2,5,3,6) 

5、有一个由数字1,2,3……,9组成的数字串(长度不超过200),问如何将M(M<=20)个加号("+")插入到这个数字串中,使所形成的算术表达式的值最小.请编一程序解决这个问题.

注意:

加号不能加在数字串的最前面或最末尾,也不应有两个或两个以上的另号相邻.M保证小于数字串的长度.

例如:

数字串798446,若需要加入两个加号,则最佳方案为79+84+46,算术表达式的值为133

程序如下:

程序中T数组用来存放子集

TOTAL=10:

N=7

FORI=1TO7:

READA(I):

NEXT

DATA8,4,1,2,5,3,7

S=0:

I=0以上初始化

60:

I=I+1往前搜索指针I加1

J=J+1:

T(J)=I元素编号,送入T数组

S=S+A(I)

IFS

IFS=TOTALTHEN200

110S=S-A(I):

J=J-1回退

120IFI

I=T(J)重新设置搜索指针

IFI=NANDJ=1THENEND

150GOTO110

200FORK=1TOJ:

PRINTA(T(K));:

NEXTK:

PRINT:

GOTO110

【题目】4×4棋盘上每行每列各摆2颗棋子,要求每一行,每一列上只能放置2个有多少种摆法程序

10DIMa(6),b(6)

20FORi=1TO6:

READa(i),b(i):

NEXTi

30DATA1,2,1,3,1,4,2,3,2,4,3,4

40i=0

50i=i+1:

t(i)=0

60t(i)=t(i)+1

70IFt(i)<=6THEN110

80i=i-1

90IFi<0THENPRINTm:

END

100GOTO200

110x=t(i):

y(a(x))=y(a(x))+1:

y(b(x))=y(b(x))+1

120IFy(a(x))>2ORy(b(x))>2THENGOTO200

130IFi<4THEN50

135m=m+1

140FORj=1TO4:

PRINTTAB(a(t(j)));"*";TAB(b(t(j)));"*";:

NEXTj

200x=t(i):

y(a(x))=y(a(x))-1:

y(b(x))=y(b(x))-1:

GOTO60

【题目】在4×4的棋盘上放置8个棋,要求每一行,每一列上只能放置2个.

【参考程序1】

算法:

8个棋子,填8次.深度为8.注意判断是否能放棋子时,两个两个为一行.

vara:

array[1..8]of0..4;

line,bz:

array[1..4]of0..2;{line数组:

每行已放多少个的计数器}

{bz数组:

每列已放多少个的计数器}

total:

integer;

procedureoutput;{输出}

vari:

integer;

begin

inc(total);write(total,':

');

fori:

=1to8dowrite(a[i]);writeln;

end;

functionok(dep,i:

integer):

boolean;

begin

ok:

=true;

ifdepmod2=0then{假如是某一行的第2个,其位置必定要在第1个之后}

if(i<=a[dep-1])thenok:

=false;

if(bz[i]=2)or(line[depdiv2]=2)thenok:

=false;

{某行或某列已放满2个}

end;

procedurefind(dep:

integer);

vari:

integer;

begin

fori:

=1to4dobegin

ifok(dep,i)thenbegin

a[dep]:

=i;{放在dep行i列}

inc(bz[i]);{某一列记数器加1}

inc(line[depdiv2]);{某一行记数器加1}

ifdep=8thenoutputelsefind(dep+1);

dec(bz[i]);{回溯}

dec(line[depdiv2]);

a[dep]:

=0;

end;

end;

end;

begin

total:

=0;fillchar(a,sizeof(a),0);fillchar(bz,sizeof(bz),0);

find

(1);

end.

【参考程序2】

算法:

某一行的放法可能性是(1,2格),(1,3格),(1,4格)....共6种放法

const

fa:

array[1..6]ofarray[1..2]of1..4=((1,2),(1,3),(1,4),(2,3),(2,4),(3,4));

{六种可能放法的行坐标}

var

a:

array[1..8]of0..4;

bz:

array[1..4]of0..2;{列放了多少个的记数器}

total:

integer;

procedureoutput;

vari:

integer;

begin

inc(total);

write(total,':

');

fori:

=1to8dowrite(a[i]);

writeln;

end;

functionok(dep,i:

integer):

boolean;

begin

ok:

=true;{判断现在的放法中,相应的两列是否已放够2个}

if(bz[fa[i,1]]=2)or(bz[fa[i,2]]=2)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 初中作文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1