ACM1培训第一次.docx
- 文档编号:25072155
- 上传时间:2023-06-04
- 格式:DOCX
- 页数:34
- 大小:84.34KB
ACM1培训第一次.docx
《ACM1培训第一次.docx》由会员分享,可在线阅读,更多相关《ACM1培训第一次.docx(34页珍藏版)》请在冰豆网上搜索。
ACM1培训第一次
ACM竞赛经典算法
计算机与信息技术学院
目录
第一课递归2
第二课排列5
第三课经典排列8
组合问题
(1)11
第四次课深度搜索14
第一课递归
一、pascal特点:
1.编写程序结构化;
2.支持递归;
3.通过使用指针,实现动态存储。
二、函数和过程的作用:
1.相对独立功能的一段程序,一般用一个子程序(函数和过程)来编写;
2.结构清楚,便于调试、修改和扩充;
3.节约程序段和内存;
三、递归
定义:
子程序自己调用自己的程序段叫递归;
使用递归的条件
1.可以把一个问题转化为一个类似自己的新问题,且问题的规模发生规律性的变化。
2.可以通过转化使问题得到解决。
3.有一个明确的结束条件。
递归实际上是个逆向思维过程,核心是求递归公式。
四、习题:
1、用递归求n!
.
程序如下:
programsample1_1;
var
n:
integer;
functionfac(n:
integer):
real;
begin
ifn=1thenbeginfac:
=1;exit;end;
fac:
=n*fac(n-1);
end;
begin
readln(n);
writeln(fac(n):
3:
0);
end.
总结:
1、递归一般用函数或过程来实现,主程序没有办法来实现递归;
2、递归要有空间想象能力;
3、需要保护的变量一定要开成局部变量。
像functionfac(n:
integer)中的n.就是局部变量。
2、斐波那契数列
f(n)=f(n-1)+f(n-2)
程序如下:
var
n:
integer;
functionf(n:
integer):
integer;
begin
if(n=1)or(n=0)thenbeginf:
=1;exit;end;
f(n):
=f(n-1)+f(n-2);
end;
begin
readln(n);
write(f(n));
end.总结:
(1)递归每执行一次,就要开辟一次局部变量,保护上一次的内容。
递归是逆向出发,先从全局出发,如何将大规模转化为小规模的问题。
(2)fac(4):
=fac(3)+fac
(2);
fac(3):
=fac
(2)+fac
(1);
Fac
(2):
=fac
(1)+fac(0)
Fac
(2):
=fac
(1)+fac(0)
重复运算多,速度慢。
3、输入一串字符,以’.’结束,倒序输出。
程序如下:
var
c:
char;
procedureprint(n:
char);
var
ch:
char;
begin
ifn=’.’thenexit;
readln(ch);
print(ch);
writeln(ch);
end;
begin
readln(c);
print(c)
end.
4、求两个整数的最大公约数(辗转相除法)
程序如下:
var
m,n:
integer;
functionfac(I,j:
integer):
integer;
begin
ifj=0thenbeginfac:
=i;exit;end;
fac:
=fac(j,imodj);
end;
begin
readln(n,m);
writeln(fac(n,m));
end.
5、求给出一个多位整数的第K位。
Fac:
=fac(xdiv10,k-1)(k>1)
Fac(x,k)=
fac:
=xmod10(k=1)
程序如下:
var
x,k:
integer;
functionfac(I,j:
integer):
integer;
begin
ifj=1thenbeginfac:
=Imod10;exit;end;
fac:
=fac(Idiv10,k-1);
end;
begin
readln(x,k);
write(fac(x,k));
end.
6、梵诺塔
Var
N:
integer;sa,sb,sc:
string;
Proceduremove(n:
integer;a,b,c:
char;varsa,sb,sc:
string;);
Begin
Ifn=1thenbeginwrite(A,’:
’,sa[1],’-)’,C);
Sc:
=sa[1]+sc;
Sa:
=copy(sa,2,length(sa)-1);
exit;end;
Move(n-1,a,c,b,sa,sc,sb);
Write(A,’:
’,sa[1],’-)’,C);
Sc:
=sa[1]+sc;
Sa:
=copy(sa,2,length(sa)-1);
Move(n-1,b,a,c,sb,sa,sc);
End;
Begin
Readln(n);
sa:
=’12345’;
sb:
=’’;
sc:
=’’;
Move(5,’A’,’B’,’C’,sa,sb,sc);
End.
第二课排列
(排列)
递归跟多重for循环一样,只不过递归可以随机控制循环的层数,可以实现循环次数的可变性,m叫递归的层数,叫深度。
N叫宽度,时间的复杂度为nm次。
控制循环的I一定是局部变量。
1、从n个自然数中取出m个数的排列(允许重复);
程序如下:
var
a:
array[1..100]ofinteger;
n,m,s:
integer;
procedureprint;
var
I:
integer;
Begin
ForI:
=1tomdo
Write(a[I]:
3);
End;
procedureplay(k:
integer)
var
I:
integer;
Begin
Ifk=m+1thenbegin
Inc(s);
Print;
Exit;
End;
ForI:
=1tondo
Begin
A[k]:
=I;
Play(k+1);
End;
End;
begin
readln(n,m);
s:
=0;
play
(1);
writeln(s);
end.
2、n个自然数中取出m个数的排列(不允许重复(n>=m);
var
a:
array[1..100]ofinteger;
b:
array[1..100]ofBoolean;
n,m,s:
integer;
procedureprint;
var
I:
integer;
Begin
ForI:
=1tomdo
Write(a[I]:
3);
End;
procedureplay(k:
integer);
var
I:
integer;
begin
ifk=m+1thenbegininc(s);print;exit;end;
forI:
=1tondo
ifb[I]thenbegina[k]:
=I;b[I]:
=false;play(k+1);b[I]:
=true;end;
end;
begin
readln(n,m);
s:
=0;
fillchar(b,sizeof(b),false);
play
(1);
writeln(s);
end.
3.限定次数,若干限定次数,即每个数都有限定次数,可用标志数组,B数组先录入限定的次数,用一次则该数组中的数减1,至到为0为止。
4.若干个不连续的数的排列
引入第3个数组C,将不规律映射到规律下标的数组当中。
例:
’PASCAL’字符串取3个字母的排列
*本题就是限次,而且不连续数的排列,可以映射到字符串去。
程序如下:
var
a:
array[1..3]ofchar;
b:
array[1..26]ofinteger;
p,c:
string;
I,s:
integer;
Procedureprint;
Var
I:
integer;
Begin
ForI:
=1to3do
Write(a[I]);
Writeln;
End;
Procedureplay(k:
integer);
Var
I:
integer;
Begin
Ifk=4thenbegininc(s);print;exit;end;
ForI:
=1tolength(c)do
Ifb[I]>0thenbegin
A[k]:
=c[I];
Dec(b[I]);
Play(k+1);
Inc(b[I]);
End;
Begin
Readln(p);
C:
=’’;
ForI:
=1tolength(p)do
Ifpos(p[I],c)=0thenbeginc:
=c+p[I];b[pos(p[i],c)]:
=1;exit;
Endelseinc(b[pos(p[I],c)];
S:
=0;
Play
(1);
Writeln(s);
End.
第三课经典排列
1、错排:
n封信,n个信封,全装错的情况
(I<>j,且不允许重复的情况)
var
a:
array[1..100]ofinteger;
b:
array[1..100]ofboolean;
n,s:
integer;
procedureprint;
var
i:
integer;
begin
fori:
=1tondo
write(a[i]:
3);
writeln;
end;
procedureplay(k:
integer);
var
i:
integer;
begin
ifk=n+1thenbeginprint;inc(s);exit;end;
fori:
=1tondo
if(i<>k)andb[i]thenbegin
a[k]:
=i;b[i]:
=false;
play(k+1);
b[i]:
=true;
end;
end;
begin
readln(n);
s:
=0;
fillchar(b,sizeof(b),true);
play
(1);
writeln(s);
end.
2、8皇后问题(任一皇后不在同一行同一列,同一斜行上)
八皇后是一个二维数组,如果用一个一维数组来存放,就可以保证行上不重,在列上再用一个数来判重,就可以保证列上不重。
var
a,b:
array[1..8]of0..8;
s,n:
integer;
functioncan(k:
integer):
boolean;
var
i:
integer;
begin
nrep:
=false;
fori:
=1tok-1do
ifabs(i-k)=abs(a[i]-a[k])thenexit;
nrep:
=true;
end;
procedureprint;
var
i,j:
integer;
begin
fori:
=1to8dobegin
forj:
=1to8do
ifa[i]=jthenwrite('*':
2)elsewrite(0:
2);
writeln;
end;
writeln('----------------------');
end;
proceduretry(k:
integer);
var
i:
integer;
begin
ifk>nthenbegininc(s);print;exit;end;
fori:
=1to8do
ifb[i]=0thenbegin
a[k]:
=i;
b[i]:
=1;
ifcan(k)thentry(k+1);
b[i]:
=0;
end;
end;
begin
n:
=8;
s:
=0;
try
(1);
writeln(s);
end.
3、由A、B、C三个字母组成长度为n的没有连续3个相同的子串。
(只讨论第k个字母加上去后是否影响到产生三个相同的子串)
type
str=string[10];
var
n,s:
integer;
functionnrep(p:
string):
boolean;
var
i:
integer;
begin
nrep:
=false;
fori:
=1tolength(p)div3do
if(copy(p,length(p)-i+1,i)=copy(p,length(p)-2*i+1,i))and
(copy(p,length(p)-2*i+1,i)=copy(p,length(p)-3*i+1,i))then
exit;
nrep:
=true;
end;
proceduretry(p:
str);
var
i:
char;
begin
iflength(p)>nthenbegininc(s);writeln(p);exit;end;
fori:
='a'to'c'do
begin
ifnrep(p+i)thentry(p+i);
end;
end;
begin
readln(n);
s:
=0;
try('');
writeln(s);
end.
4、九连环
(九连环的移动规则:
1、第1位可以随意变;2、第i位改变时,只要i-1位为0,前面各位都为1,则本位可变。
)
var
a,b:
string;
i:
integer;
procedureplay(k:
integer;c:
char);
var
i:
integer;
begin
ifa[k]=cthenexit;
ifk=1thena[k]:
=celsebegin
play(k-1,'0');
fori:
=k-2downto1do
play(i,'1');
a[k]:
=c;
end;
writeln(a);
end;
begin
readln(a);
readln(b);
fori:
=length(a)downto1do
play(i,b[i]);
end.
组合问题
(1)
1、从n个自然数中取m个数的组合;
var
a:
array[0..100]ofinteger;
n,m,s:
integer;
procedureprint;
var
i:
integer;
begin
fori:
=1tomdo
write(a[i]:
4);
writeln;
end;
proceduretry(k:
integer);
var
i:
integer;
begin
ifk>mthenbegininc(s);print;exit;end;
fori:
=a[k-1]+1tondo
begin
a[k]:
=i;
try(k+1);
end;
end;
begin
readln(n,m);
s:
=0;
a[0]:
=0;
try
(1);
writeln(s);
end.
2.输入一个正整数,拆分成正整数的和,求所有的情况。
(是组合问题,但允许重复)
程序如下:
var
a:
array[0..100]ofinteger;
n,s:
integer;
procedureprint(k:
integer);
var
i:
integer;
begin
write(n,'=',a[1]);
fori:
=2tokdo
write('+',a[i]);
writeln;
end;
proceduretry(k,p:
integer);
var
i:
integer;
begin
ifp=0thenbeginprint(k-1);inc(s);exit;end;
a[k]:
=p;try(k+1,0);
fori:
=a[k-1]topdiv2do
begina[k]:
=i;try(k+1,p-i);end;
end;
begin
s:
=0;
readln(n);
a[0]:
=1;
try(1,n);
writeln(s);
end.
3.分解质因数
程序如下:
var
a:
array[0..100]ofinteger;
n:
integer;
procedureprint(k:
integer);
var
i:
integer;
begin
write(n,'=',a[1]);
fori:
=2tokdo
write('*',a[i]);
writeln;
end;
functionyes(p:
integer):
boolean;
var
i:
integer;
begin
yes:
=false;
fori:
=2totrunc(sqrt(p))do
ifpmodi=0thenexit;
yes:
=true;
end;
procedureplay(k,p:
integer);
var
i:
integer;
begin
ifp=1thenbeginprint(k-1);exit;end;
ifyes(p)thenbegina[k]:
=p;play(k+1,1);end;
fori:
=a[k-1]totrunc(sqrt(p))do
if(i>1)and(pmodi=0)thenbegina[k]:
=i;play(k+1,pdivi);end;
end;
begin
readln(n);
a[0]:
=2;
play(1,n);
end.
第四次课深度搜索
在我们遇到的一些问题当中,有些问题我们不能够确切的找出数学模型,即找不出一种直接求解的方法,解决这一类问题,我们一般采用搜索的方法解决。
搜索就是用问题的所有可能去试探,按照一定的顺序、规则,不断去试探,直到找到问题的解,试完了也没有找到解,那就是无解,试探时一定要试探完所有的情况(实际上就是穷举);
对于问题的第一个状态,叫初始状态,要求的状态叫目标状态。
搜索就是把规则应用于实始状态,在其产生的状态中,直到得到一个目标状态为止。
产生新的状态的过程叫扩展(由一个状态,应用规则,产生新状态的过程)
搜索的要点:
(1)初始状态;
(2)重复产生新状态;
(3)检查新状态是否为目标,是结束,否转
(2);
如果搜索是以接近起始状态的程序依次扩展状态的,叫宽度优先搜索。
如果扩展是首先扩展新产生的状态,则叫深度优先搜索。
深度优先搜索
深度优先搜索用一个数组存放产生的所有状态。
(1)把初始状态放入数组中,设为当前状态;
(2)扩展当前的状态,产生一个新的状态放入数组中,同时把新产生的状态设为当前状态;
(3)判断当前状态是否和前面的重复,如果重复则回到上一个状态,产生它的另一状态;
(4)判断当前状态是否为目标状态,如果是目标,则找到一个解答,结束算法。
(5)如果数组为空,说明无解。
(6)转到(2)
对于pascal语言来讲,它支持递归,在递归时可以自动实现回溯(利用局部变量)所以使用递归编写深度优先搜索程序相对简单,当然也有非递归实现的算法。
1、迷宫
程序如下:
const
d:
array[1..4,1..4]ofinteger=((1,1,0,0),(0,1,1,1),(1,1,0,1),(0,1,1,1));
c:
array[1..4,1..2]of-1..1=((0,1),(0,-1),(1,0),(-1,0));
var
a:
array[1..16,1..2]ofinteger;
i,j:
integer;
procedureplay(k:
integer);
var
i:
integer;
begin
if(a[k,1]=4)and(a[k,2]=4)then
begin
fori:
=1tokdo
write('(',a[i,1],',',a[i,2],')');
writeln;
readln;
exit;end;
fori:
=1to4do
if(a[k,1]+c[i,1]>0)and(a[k,1]+c[i,1]<5)and(a[k,2]+c[i,2]>0)and(a[k,2]+c[i,2]<5)then
ifd[a[k,1],a[k,2]]=1thenbegin
d[a[k,1],a[k,2]]:
=2;
a[k+1,1]:
=a[k,1]+c[i,1];
a[k+1,2]:
=a[k,2]+c[i,2];
play(k+1);
d[a[k,1],a[k,2]]:
=1;
end;
end;
begin
fillchar(a,sizeof(a),0);
a[1,1]:
=1;a[1,2]:
=1;
play
(1);
end.
2、8数码
程序如下:
type
node=array[1..3,1..3]of0..8;
const
st:
node=((2,8,3),(1,6,4),(7,0,5));
gl:
node=((1,2,3),(8,0,4),(7,6,5));
rl:
array[1..4,1..2]of-1..1=((0,1),(0,-1),(1,0),(-1,0));
var
a:
array[1..20]ofnode;
functionresult(k:
integer):
boolean;
var
i,x,y:
integer;
begin
result:
=false;
forx:
=1to3do
fory:
=1to3do
ifa[k,x,y]<>gl[x,y]thenexit;
result:
=true;
end;
procedurelook(k:
integer;varx,y:
integer);
var
i,j:
integer;
begin
fori:
=1to3do
forj:
=1to3do
ifa[k,i,j]=0thenbeginx:
=i;y:
=j;end;
end;
procedureprint(k:
integer);
var
i,x,y:
integer;
begin
fori:
=1tokdo
begin
writeln('step:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ACM1 培训 第一次