搜索试题集.docx
《搜索试题集.docx》由会员分享,可在线阅读,更多相关《搜索试题集.docx(54页珍藏版)》请在冰豆网上搜索。
搜索试题集
说明:
本文件部分程序来自一些信息学奥赛的参考书,如早年的信息学高级本等。
时间关系,未能一一列出出处,请原作者见谅。
部分图尚未画出,争取尽快补上。
【execans.2为深度优先搜索,广度优先搜索类,及技巧性题目题解】
【题目1】N皇后问题(八皇后问题的扩展)
【题目2】排球队员站位问题
【题目3】把自然数N分解为若干个自然数之和。
【题目4】把自然数N分解为若干个自然数之积。
【题目5】马的遍历问题。
【题目6】加法分式分解
【题目7】地图着色问题
【题目8】在n*n的正方形中放置长为2,宽为1的长条块,
【题目9】找迷宫的最短路径。
(广度优先搜索算法)
【题目10】火车调度问题
【题目11】农夫过河
【题目12】七段数码管问题。
【题目13】把1-8这8个数放入下图8个格中,要求相邻的格(横,竖,对角线)上填的数不连续.
【题目14】在4×4的棋盘上放置8个棋,要求每一行,每一列上只能放置2个.
【题目15】迷宫问题.求迷宫的路径.(深度优先搜索法)
【题目16】一笔画问题
【题目17】城市遍历问题.
【题目18】棋子移动问题
【题目19】求集合元素问题(1,2x+1,3X+1类)
================================================================================[返回头部]
================================================================================
【题目】N皇后问题(含八皇后问题的扩展,规则同八皇后):
在N*N的棋盘上,放置N个皇后,要求每一横行每一列,每一对角线上均只能放置一个皇后,问可能的方案及方案数。
constmax=8;
vari,j:
integer;
a:
array[1..max]of0..max;{放皇后数组}
b:
array[2..2*max]ofboolean;{/对角线标志数组}
c:
array[-(max-1)..max-1]ofboolean;{\对角线标志数组}
col:
array[1..max]ofboolean;{列标志数组}
total:
integer;{统计总数}
procedureoutput;{输出}
vari:
integer;
begin
write('No.':
4,'[',total+1:
2,']');
fori:
=1tomaxdowrite(a[i]:
3);write('');
if(total+1)mod2=0thenwriteln;inc(total);
end;
functionok(i,dep:
integer):
boolean;{判断第dep行第i列可放否}
begin
ok:
=false;
if(b[i+dep]=true)and(c[dep-i]=true){and(a[dep]=0)}and
(col[i]=true)thenok:
=true
end;
proceduretry(dep:
integer);
vari,j:
integer;
begin
fori:
=1tomaxdo{每一行均有max种放法}
ifok(i,dep)thenbegin
a[dep]:
=i;
b[i+dep]:
=false;{/对角线已放标志}
c[dep-i]:
=false;{\对角线已放标志}
col[i]:
=false;{列已放标志}
ifdep=maxthenoutput
elsetry(dep+1);{递归下一层}
a[dep]:
=0;{取走皇后,回溯}
b[i+dep]:
=true;{恢复标志数组}
c[dep-i]:
=true;
col[i]:
=true;
end;
end;
begin
fori:
=1tomaxdobegina[i]:
=0;col[i]:
=true;end;
fori:
=2to2*maxdob[i]:
=true;
fori:
=-(max-1)tomax-1doc[i]:
=true;
total:
=0;
try
(1);
writeln('total:
',total);
end.
【测试数据】
n=8八皇后问题
No.[1]15863724No.[2]16837425
No.[3]17468253No.[4]17582463
No.[5]24683175No.[6]25713864
No.[7]25741863No.[8]26174835
No.[9]26831475No.[10]27368514
No.[11]27581463No.[12]28613574
No.[13]31758246No.[14]35281746
No.[15]35286471No.[16]35714286
No.[17]35841726No.[18]36258174
No.[19]36271485No.[20]36275184
No.[21]36418572No.[22]36428571
No.[23]36814752No.[24]36815724
No.[25]36824175No.[26]37285146
No.[27]37286415No.[28]38471625
No.[29]41582736No.[30]41586372
No.[31]42586137No.[32]42736815
No.[33]42736851No.[34]42751863
No.[35]42857136No.[36]42861357
No.[37]46152837No.[38]46827135
No.[39]46831752No.[40]47185263
No.[41]47382516No.[42]47526138
No.[43]47531682No.[44]48136275
No.[45]48157263No.[46]48531726
No.[47]51468273No.[48]51842736
No.[49]51863724No.[50]52468317
No.[51]52473861No.[52]52617483
No.[53]52814736No.[54]53168247
No.[55]53172864No.[56]53847162
No.[57]57138642No.[58]57142863
No.[59]57248136No.[60]57263148
No.[61]57263184No.[62]57413862
No.[63]58413627No.[64]58417263
No.[65]61528374No.[66]62713584
No.[67]62714853No.[68]63175824
No.[69]63184275No.[70]63185247
No.[71]63571428No.[72]63581427
No.[73]63724815No.[74]63728514
No.[75]63741825No.[76]64158273
No.[77]64285713No.[78]64713528
No.[79]64718253No.[80]68241753
No.[81]71386425No.[82]72418536
No.[83]72631485No.[84]73168524
No.[85]73825164No.[86]74258136
No.[87]74286135No.[88]75316824
No.[89]82417536No.[90]82531746
No.[91]83162574No.[92]84136275
total:
92
对于N皇后:
┏━━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┓
┃皇后N│4│5│6│7│8│9│10┃
┠───┼──┼──┼──┼──┼──┼──┼──┨
┃方案数│2│10│4│40│92│352│724┃
┗━━━┷━━┷━━┷━━┷━━┷━━┷━━┷━━┛
【题目】排球队员站位问题[返回头部]
┏━━━━━━━━┓图为排球场的平面图,其中一、二、三、四、五、六为位置编号,
┃ ┃二、三、四号位置为前排,一、六、五号位为后排。
某队比赛时,
┃ ┃一、四号位放主攻手,二、五号位放二传手,三、六号位放副攻
┠──┬──┬──┨手。
队员所穿球衣分别为1,2,3,4,5,6号,但每个队
┃四│三│二┃员的球衣都与他们的站位号不同。
已知1号、6号队员不在后排,
┠──┼──┼──┨2号、3号队员不是二传手,3号、4号队员不在同一排,5号、
┃五│六│一┃6号队员不是副攻手。
┗━━┷━━┷━━┛编程求每个队员的站位情况。
【算法分析】本题可用一般的穷举法得出答案。
也可用回溯法。
以下为回溯解法。
【参考程序】
typesset=setof1..6;
vara:
array[1..6]of1..6;
d:
array[1..6]ofsset;
i:
integer;
procedureoutput;{输出}
begin
ifnot((a[3]in[2,3,4])=(a[4]in[2,3,4]))then
begin{3,4号队员不在同一排}
write('number:
');fori:
=1to6dowrite(i:
8);writeln;
write('weizhi:
');fori:
=1to6dowrite(a[i]:
8);writeln;
end;
end;
proceduretry(i:
integer;s:
sset);{递归过程i:
第i个人,s:
哪些位置已安排人了}
var
j,k:
integer;
begin
forj:
=1to6dobegin{每个人都有可能站1-6这6个位置}
if(jind[i])andnot(jins)thenbegin
{j不在d[i]中,则表明第i号人不能站j位.j如在s集合中,表明j位已排人了}
a[i]:
=j;{第i人可以站j位}
ifi<6thentry(i+1,s+[j]){未安排妥,则继续排下去}
elseoutput;{6个人都安排完,则输出}
end;
end;
end;
begin
fori:
=1to6dod[i]:
=[1..6]-[i];{每个人的站位都与球衣的号码不同}
d[1]:
=d[1]-[1,5,6];
d[6]:
=d[6]-[1,5,6];{1,6号队员不在后排}
d[2]:
=d[2]-[2,5];
d[3]:
=d[3]-[2,5];{2,3号队员不是二传手}
d[5]:
=d[5]-[3,6];
d[6]:
=d[6]-[3,6];{5,6号队员不是副攻手}
try(1,[]);
end.
【题目】把自然数N分解为若干个自然数之和。
[返回头部]
【参考答案】
n│total5│7
6│11
7│15
10│42
100│190569291
【参考程序】
varn:
byte;num:
array[0..255]ofbyte;total:
word;
procedureoutput(dep:
byte);
varj:
byte;
begin
forj:
=1todepdowrite(num[j]:
3);writeln;inc(total);
end;
procedurefind(n,dep:
byte);{N:
待分解的数,DEP:
深度}
vari,j,rest:
byte;
begin
fori:
=1tondo{每一位从N到1去试}
ifnum[dep-1]<=ithen{保证选用的数大于前一位}
begin
num[dep]:
=i;
rest:
=n-i;{剩余的数进行下一次递归调用}
if(rest>0)thenbeginfind(rest,dep+1);end
elseifrest=0thenoutput(dep);{刚好相等则输出}
num[dep]:
=0;
end;
end;
begin{主程序}
writeln('inputn:
');readln(n);
fillchar(num,sizeof(num),0);
total:
=0;num[0]:
=0;
find(n,1);
writeln('sum=',total);
end.
【题目】[返回头部]
把自然数N分解为若干个自然数之积。
【参考程序】
varpath:
array[1..1000]ofinteger;
total,n:
integer;
procedurefind(k,sum,dep:
integer);{K:
}
varb,d:
Integer;
begin
ifsum=nthen{积等于N}
begin
write(n,'=',path[1]);
ford:
=2todep-1dowrite('*',path[d]);
writeln;inc(total);
exit;
end;
ifsum>nthenexit;{累积大于N}
forb:
=trunc(n/sum)+1downtokdo{每一种可能都去试}
begin
path[dep]:
=b;
find(b,sum*b,dep+1);
end;
end;
begin
readln(n);total:
=0;
find(2,1,1);writeln('total:
',total);
readln;
end.
【题目】[返回头部]
马的遍历问题。
在N*M的棋盘中,马只能走日字。
马从位置(x,y)处出发,把
棋盘的每一格都走一次,且只走一次。
找出所有路径。
【参考程序】{深度优先搜索法}
constn=5;m=4;
fx:
array[1..8,1..2]of-2..2=((1,2),(2,1),(2,-1),(1,-2),(-1,-2),(-2,-1),
(-2,1),(-1,2));{八个方向增量}
var
dep,i:
byte;x,y:
byte;
cont:
integer;{统计总数}
a:
array[1..n,1..m]ofbyte;{记录走法数组}
procedureoutput;{输出,并统计总数}
varx,y:
byte;
begin
cont:
=cont+1;writeln;
writeln('count=',cont);
fory:
=1tondobegin
forx:
=1tomdowrite(a[y,x]:
3);writeln;
end;{readln;halt;}
end;
procedurefind(y,x,dep:
byte);
vari,xx,yy:
integer;
begin
fori:
=1to8do
begin
xx:
=x+fx[i,1];yy:
=y+fx[i,2];{加上方向增量,形成新的坐标}
if((xxin[1..m])and(yyin[1..n]))and(a[yy,xx]=0)then
{判断新坐标是否出界,是否已走过?
}
begin
a[yy,xx]:
=dep;{走向新的坐标}
if(dep=n*m)thenoutput
elsefind(yy,xx,dep+1);{从新坐标出发,递归下一层}
a[yy,xx]:
=0{回溯,恢复未走标志}
end;
end;
end;
begin
cont:
=0;
fillchar(a,sizeof(a),0);
dep:
=1;
writeln('inputy,x');readln(y,x);
{x:
=1;y:
=1;}
if(y>n)or(x>m)thenbeginwriteln('x,yerror!
');halt;end;
a[y,x]:
=1;
find(y,x,2);
ifcont=0thenwriteln('Noanswer!
')elsewrite('TheEnd!
');
readln;
end.
【题目】[返回头部]
加法分式分解。
如:
1/2=1/4+1/4.找出所有方案。
输入:
NMN为要分解的分数的分母
M为分解成多少项
【参考程序】
programfenshifenjie;
constnums=5;
var
t,m,dep:
integer;
n,maxold,max,j:
longint;
path:
array[0..nums]oflongint;
maxok,p:
boolean;
sum,sum2:
real;
procedureprint;
vari:
integer;
begin
t:
=t+1;
ifmaxok=truethenbeginmaxold:
=path[m];maxok:
=false;end;
write('NO.',t);
fori:
=1tomdowrite('',path[i]:
4);writeln;
ifpath[1]=path[m]thenbeginwriteln('Ok!
total:
',t:
4);readln;halt;end;
end;
procedureinput;
begin
writeln('inputN:
');readln(n);
writeln('inputM(M<=',nums:
1,'):
');readln(m);
if(n<=0)or(m<=0)or(m>4)or(n>maxlongint)
thenbeginwriteln('InvalidInput!
');readln;halt;end;
end;
functionsum1(ab:
integer):
real;
vara,b,c,d,s1,s2:
real;
i:
integer;
begin
ifab=1then
sum1:
=1/path[1]
else
begin
a:
=path[1];
b:
=1;
c:
=path[2];
d:
=1;
fori:
=1toab-1do
begin
s2:
=(c*b+a*d);
s1:
=(a*c);
a:
=s1;
b:
=s2;
c:
=path[i+2];
end;
sum1:
=s2/s1;
end;
end;
procedureback;
begin
dep:
=dep-1;
ifdep<=m-2thenmax:
=maxold;
sum:
=sum-1/path[dep];
j:
=path[dep];
end;
procedurefind;
begin
repeat
dep:
=dep+1;
j:
=path[dep-1]-1;
p:
=false;
repeat
j:
=j+1;
if(dep<>m)and(j<=max)then
if(sum+1/j)>=1/nthenp:
=false
elsebegin
p:
=true;
path[dep]:
=j;
sum:
=sum+1/path[dep];
end
elseifj>maxthenback;
ifdep=mthenbegin
path[dep]:
=j;
sum2:
=sum1(m);
if(sum2)>1/nthenp:
=false;
if(sum2)=1/nthenbeginprint;
max:
=j;
back;
end;
if(sum2<1/n)thenback;
if(j>=max)thenback;
end;
untilp
untildep=0;
end;
begin
INPUT;
maxok:
=true;
fort:
=0tomdopath[t]:
=n;
dep:
=0;t:
=0;sum:
=0;
max:
=maxlongint;
find;
readln;
end.
【题目】[返回头部]
地图着色问题
【参考程序1】
constlin:
array[1..12,1..12]of0..1{区域相邻数组