程序填空专练一答案Word文档下载推荐.docx
《程序填空专练一答案Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《程序填空专练一答案Word文档下载推荐.docx(17页珍藏版)》请在冰豆网上搜索。
ifa[i]<
a[j]then
begintemp:
=a[i];
a[i]:
=a[j];
a[j]:
=tempend;
=2tomaxndo
if__③__thena[i]:
=-a[i];
tail:
current:
=1;
while_____④_____do
begin
whilea[current]<
0docurrent:
=current+1;
=tail+1;
a[tail]:
=__⑤__;
current:
=current+1
end;
if___⑥__thenbegintail:
=0end;
=1totaildowrite(a[i]:
5);
writeln
end.
[解答]
程序的思想已经不能再清楚了,因为要排序(很明显是冒泡排序),所以:
①maxn-1
②i+1
那么如何删除呢?
先分析一下变量的含义,current和tail分别表示队列的头尾指针。
再看删的过程:
好象是先做标记(置为负!
),然后从队首current开始找第1个没被做标记(>
0)的数,把它放到当前队尾tail的下一个位置。
所以:
③a[i]=abs(a[i-1])
④(current<
=maxn)and(a[current]<
>
0)
⑤a[current]
⑥(a[tail]<
0)and(a[current]=0)
2.关键变量+特定的思想方法+灵感(1995年初中组2)
找出小于33的6个正整数,用这些整数进行加法运算,使得包括原来的整数在内能组成尽可能多的不同整数。
例如:
用2,3,5这三个数能可组成下面的数:
2,3,5,2+3=5(但5已经存在)
2+5=7,3+5=8,2+3+5=10
所以用2,3,5能组成6个不同的数。
程序要求:
输出所选的这6个数,以及能组成不同整数的个数。
算法提要:
选择的这6个数,用来组成数时应该尽可能不重复,引入数组A保存找出的这6个整数。
主要程序段:
A[1]:
=1;
t:
=0;
Fori:
=2to6do
_________①________;
forj:
=1toi-1dos:
=______②_______;
a[i]:
=_______③_______;
Fori:
=1to6do
Begin
t:
=______④______;
WRITE(a[i],'
'
);
End;
Writeln('
能组成不同整数的个数:
'
t)
解答:
首先,根据蓝色的程序段,我们应该判断出③应该和s相关,而②是为了计算s,所以本题的关键是变量s的含义。
不要着急,我们研究一下题目的例子和算法提要,发现:
选择的6个数(a[i])应该尽可能不重复;
且a[i]>
a[i-1]而a[i]还要尽可能小;
假设现在已求出了a[1]…a[i-1],那么为了满足“能组成尽可能多的不同整数”,则a[i]应该取a[1]+a[2]+…+a[i-1]+1,这样必然要设一个累加器,再看看程序:
)还真是!
所以得到:
①初始化s:
②累加s+a[j];
③赋值,注意多加1:
s+1;
那么④怎么填呢?
它表示能组成的不同整数的个数,那为什么要扫描一遍数组呢?
感觉也应该是累加!
其实我们应该充分发挥上面已填好的程序段,发现:
6个数为:
12481632(哦,难怪说小于33!
让我更加坚信上面做的是对的!
),很明显是二进制数的问题吗?
本质上就是一个求一个6位的二进制数最多能表示多少状态?
答案为:
20+21+22+23+24+25=1+2+4+8+16+32。
不要激动,看题目④填什么?
累加:
t+a[i]。
3.复杂的问题描述+简单的程序+细心地处理细节问题(1995年高中组3)
设有一个实数,以字符串形式存放于数组x中,用x:
array[1..N]ofchar表示。
其中x[1]若为'
-'
,表示负数;
若为'
+'
、'
.'
或'
,则表示正数。
若为数字,也认为是正数。
例如x=('
'
2'
0'
3'
5'
%'
)则表示203.5
x=('
1'
)则表示-1.2
约定:
在字符串x中,除x[1]外,其后可以包含有若干个'
与'
,但仅以第一次出现的为准,空格不起任何作用,并以字符'
作为结束标志。
将输入的字符串还原成实数输出(小数点后无用的0应除去),还原的结果以下列形式存放(不需要输出)。
F:
数符。
正数放0,负数放1。
A:
array[1..N]ofinteger;
存放数字,不放小数点。
K:
表示A中有效数字的个数。
J:
表示小数点后的位数。
数203.24,还原后结果的存放是:
F=0
A=(2,0,3,2,4)
K=5
J=2
又如:
数-33.0740,还原后结果的存放是:
F=1
A=(3,3,0,7,4)
J=3
x:
array[1..10]ofchar;
可放长度定为10;
首先读入字符串,然后处理数的符号,在还原的过程中,需要判定整数部分与小数部分,同时去除多余的空格和小数点,并约定输入是正确的,不用作出错检查。
只要程序段:
ForI:
=1to10doa[I]:
=1to10doread(x[I]);
J:
f:
k:
b:
Ifx[1]='
thenbegin
____________①____________;
____________②____________;
End
Elseifx[1]:
='
thenI:
=2
ElseI:
While________③_________doI:
=I+1;
While__________④___________do
BEGIN
If(x[I]>
)and(x[I]<
9'
)Thenbegin
k:
=k+1;
________⑤_______;
Ifb=1then______⑥_______;
end
Elseif(x[I]='
)and(b=0)thenb:
I:
=I+1
END;
Ifj>
0thenwhilea[k]=0dobegin
__________⑦_________
__________⑧_________
显然,蓝色的程序段是用来处理实数的符号的,所以根据约定①应该是设置负数标记,即f:
根据else后面的句子,发现i为循环扫描的指针,所以②应该是确定下一位置,即i:
=2;
③很明显是过滤掉空格!
所以填:
(x[i]=’’)and(i<
10);
④也很明显,一个大循环,判断字符串是否扫描结束,即:
x[i]<
’%’
再看看b变量的含义:
根据else子句,发现b=1表示整数部分结束!
所以⑤是把一个数字字符转换成数字填到数组a中(a[k]:
=ord(x[i])-48);
⑥填j:
=j+1;
(j表示小数点后的位数);
⑦⑧很明显,是处理有小数、并且有多余的0的情况,所以为:
j:
=j-1;
k:
=k-1;
小结:
注意程序前前后后看,发现变量的作用和含义!
4.典型算法+数据结构(1996年高中组1/初中组3)
四色问题:
设有下列形状的图形:
(N=8),其编号
为1,2,……,N。
图形之间的相邻关系用下面的邻接矩阵表示:
1
2
3
4
5
6
7
8
其中:
1——相邻,0——不相邻。
[程序要求]将上面图形的每一个部分涂上红
(1),黄
(2),蓝(3),绿(4)四种颜色之一,要求相邻的部分有不同颜色。
输入方式:
邻接矩阵。
输出方式:
区域、颜色。
[算法描述]用数组R:
ARRAY[1..N,1..N]OF0..1表示相邻关系,S:
ARRAY[1..N]OFINTEGER表示颜色。
采用回溯的方法,首先给第一个图形涂上红色
(1),然后在下面的图形中依次涂上其他颜色,当有矛盾时回溯解决。
[程序]
programexp2(inpuT,output);
Constn=8;
VarI,j,k:
R:
Array[1..n,1..n]of0..1;
S:
Array[1..n]ofinteger;
Begin
ForI:
=1tondo
Forj:
=1tondoread(R[I,j]);
readln
①;
I:
=2;
whileI<
=ndo
while(j<
=4)and(I<
=n)do
while②dok:
ifk<
Ithen③
elsebegin
④;
=I+1;
=1
4thenbegin
=I-1;
⑤
=1tondowriteln(I,'
s[I])
End.
解答:
邻接矩阵+回溯法,步骤略,答案如下:
①S[1]:
=1;
②(K<
I)AND(S[K]*R[I,J])<
J
③J:
=J+1;
④S[I]:
=J;
⑤J:
=S[I]+1;
5.子程序及参数(1999年初中组)
[问题描述]
下面程序的功能是从键盘读取A,B数组的元素,A,B数组均已从小到大排好序(无相同元素),现将A,B合并为数组C,同样要求数组C也是从小到大排好序(有相同元素时只保留一个)。
程序中N表示数组A,B的长度,i,j,k分别表示数组A,B,C的取数或存数的指针。
[程序清单]
programexcp3;
constn=8;
m=2*n;
typearr1=array[1..n]ofinteger;
arr2=array[1..m]ofinteger;
vara,b:
arr1;
c:
arr2;
i,j,k:
procedurecopy(x:
vary:
vari,j:
integer);
i:
=i+1;
y[i]:
=x[j];
end;
begin
=1tondoread(a[i]);
readln;
=1tondoread(b[i]);
___________①________
while__________②__________do
b[j]thencopy(a,c,k,i)
elseifb[j]<
a[i]thencopy(b,c,k,j)
copy(a,c,k,i);
__________③__________
while__________④___________docopy(a,c,k,i);
while__________⑤___________docopy(b,c,k,j);
=1tokdowrite(c[i]:
4);
writeln;
就本题而言,算法和题目本身对选手很清楚!
线性表的归并操作在NOIP中考过多次,不管是用数组来操作还是用链表操作;
甚至还有一些题目是它的变形(比如多项式的加法)。
本题中的copy过程是关键,好在题目并没有考到过程调用的语句(关键是参数的书写),所以下面只要理解了过程的作用和4个参数的含义,题目就会很容易了。
答案:
①k:
=0
②(i<
=n)and(j<
=n)
③j:
=j+1
④i<
=n
⑤j<
6.特定的算法(1999年高中组2)
[问题描述]用生成法求出1,2,…,r的全排列(r<
=8)
[算法过程]用数组:
a:
array[1..r]ofinteger;
表示排列;
初始化时,a[I]:
=1(I=1,2,….f)
设中间的某一个排列为a[1],a[2],…a[r],则求出下一个排列的算法为:
(1)从后面向前找,直到找到一个顺序为止(设下标为j,则a[j-1]<
a[j])
(2)从a[j]-a[r]中,找出一个a[k]比a[j-1]大的最小元素
(3)将a[j-1]与a[K]交换
(4)将a[j],a[j+1]……a[r]由小到大排序。
programexp4;
constr=7;
varn,i,s,k,j,i1,t:
intger;
array[1..r]ofinteger;
procedureprint1;
varik:
forik:
=1tordowrite(a[ik]:
8);
writeln;
end
=1tordo__________①__________;
print1;
s:
=2tordos:
=s*i;
=s-1;
=__________②__________do
begin
=r;
while__________③_________doj:
步骤1
=j;
fori1:
=j+1tordo
if__________④_________thenk:
=i1;
步骤2
=a[j-1];
a[j-1]:
=a[k];
a[k]:
=t;
步骤3
fori1:
=jtor-1do
fork:
=i1+1tordo
if__________⑤___________then步骤4
t:
=a[i1];
a[i1]:
print1;
end.
解题步骤:
1)首先,本题给出了关键而详细的算法说明,但没有给一个样例,下面我们结合一个中间状态数据,看看如何生成下一个状态数据。
18734652
经过4步后得到:
18735246
这样,你对程序的逻辑过程就很清楚了!
2)把程序分段:
如上4中颜色。
红色的过程表示输出,没问题!
蓝色的显然是初始化,所以①填:
=i;
绿色的表示统计总的方案数(并且已经输出了一个,所以-1);
紫色的程序段很明显是解决算法说明的4个步骤的,下面重点解决!
3)看看4个步骤分别对应着哪些语句?
注意对应和找关键动作!
②应该填:
1tos或sdownto1,但不能写成2tos;
③填:
a[j-1]>
a[j]
④填:
(a[i1]>
a[j-1])and(a[i1]<
a[k])复合条件缺一不可,经常考!
⑤填:
a[i1]>
a[k],显然是从小到大冒泡排序用。
小结:
重视题目给出的每一个信息与程序中的哪些语句对应;
如果没有样例,自己找一个典型的,运行运行找出规律;
程序的分块!
7.数据结构题(1999年高中组试题)
[问题描述]求一棵树的深度与宽度。
[算法说明]树可用数组tree:
array[1..n,1..5]ofinteger;
其中:
tree[I,1]表示结点号;
tree[I,2]——tree[I,5]所属结点
如上图可表示为:
12340
25670
38000
491000
50000
60000
7111200
80000
90000
100000
110000
1213000
130000
在求解的过程中,用到数组G:
ARRAY[1..N,1..7]OFINTEGER;
G[I,1]表示父结点,G[I,2]表示层次,
G[I,3]表示本结点号,G[I,4]——G[I,7]表示子女结点;
同时,设2个指针SP1(取数指针),SP2(存数指针)
[程序清单]:
programexGp3;
constn=13;
vari,j,k,sp1,sp2,n1,n2,jmax,p:
tree:
g:
array[1..n,1..7]ofinteger;
=1tondo
tree[i,1]:
forj:
=2to5doread(tree[i,j]);
sp1:
sp2:
g[1,1]:
g[1,2]:
g[1,3]:
=4to7dog[1,i]:
=tree[1,i-2];
while__________①_________do
p:
=g[sp1,2];
n2:
=g[sp1,3];
_________②________;
=4;
while_________③_________do
n1:
=g[sp1,j];
__________④_________;
g[sp2,1]:
=n2;
g[sp2,2]:
=p;
g[sp2,3]:
=n1;
=1to4dog[sp2,i+3]:
=tree[n1,i+1];
__________⑤_________;
writeln('
maxd='
g[sp2,2]);
=g[1,2];
jmax:
=2tosp2do
if__________⑥__________thenj:
ifj>
jmaxthenjmax:
__________⑦________;
=g[I,2];
max1='
jmax);
end.
1)本题的数据结构含义,首先要搞清楚:
tree[i,j]存储编号为i的结点的第j号孩子(2<
=j<
=5,即最多4个孩子),tree[i,j]=0表示不存在;
g[i,k]是一个队列,sp1为读取队列用的指针,sp2为存储队列用的指针。
g[i,1]存储i的父结点,g[i,2]存储i所在的层次,g[i,3]存储本结点的编号i,g[i,4],g[i,5],g[i,6],g[i,7]存储i的孩子结点编号。
列出g的表格形式,以便更加直观!
2)程序关键在红色和蓝色的两段。
先看红色段,①显然表示队列非空时做……,所以应该填:
sp1<
=sp2;
变量p是用来存放层次的,所以②填:
p:
=p+1;
为该结点的孩子结点准备好层次;
n2是表示当前处理的结点号,n1是表示n2的孩子结点号(用j循环),③这个地方的循环是为了遍历本结点的所有孩子,所以③填:
g[sp1,j]<
0;
那么④⑤干什么呢?
不要忘记一个重要的事情,队列的读取都需要移动指针(sp1,sp2),所以正好,④为下面的存入操作作准备,即sp2:
=sp2+1;
⑤为下一个结点的遍历操作作准备,即读指针下移:
sp1:
=sp1+1;
3)下面看看蓝色的程序段,目的很明显是为了输出。
再注意题目的目的:
输出树的宽度和深度!
深度简单,其实就是g[sp2,2]。
题目也没有考你!
那么剩下的问题显然就是为了求宽度。
方法也很简单,就是求每一层的宽度(即g[I,4]~g[I,7]中的非0个数,或者按本题的方法是看g[I,2]中最多有几个数相同),然后打擂台找出最大值。
因此,⑥填:
g[I,2]=k,计算层次相同的元素个数