搜索与回溯练习(二)
2016-02-02 22:21
218 查看
回溯算法_迷宫问题
AYYZOJ p1418
COGS p1105
【问题描述】
有一个m*n格的迷宫(表示有m行、n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这m*n个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-l表示无路)。
【输入】
第一行是两个数m,n(1<m,n<15),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。
【输出】
所有可行的路径,描述一个点时用(x,y)的形式,除开始点外,其他的都要用“->”表示方向。
如果没有一条可行的路则输出-1。
【样例】
maze.in
5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6
maze.out
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
【样例解释】:由于搜索时试探的顺序不一样,路线方案也就不同,输出样例中试探方向是按左、上、右、下的顺序试探的,编程时请按此顺序试探,否则可能结果与标准数据输出不一致。
【算法分析】
用一个a数组来存放迷宫可走的情况,另外用一个数组b来存放哪些点走过了。每个点用两个数字来描述,一个表示行号,另一个表示列号。对于某一个点(x,y),四个可能走的方向的点描述如下表:
对应的位置为:(x-1, y),(x, y+1),(x+1, y),(x, y-1)。所以每个点都要试探四个方向,如果没有走过(数组b相应的点的值为0)且可以走(数组a相应点的值为1)同时不越界,就走过去,再看有没有到达终点,到了终点则输出所走的路,否则继续走下去。
注意:参考程序中的遍历顺序是左上右下,cogs中遍历顺序是上左右下。
参考程序
搜索算法_最小拉丁方阵
AYYZOJ p1453
问题描述:
输入 N,求 N 阶最小的拉丁方阵 (2 ≤ N ≤ 9)。N 阶拉丁方阵为每一行、每一列都是数字1到N,且每个数字只出现一次。最小拉丁方阵是将方阵的一行一行数连接在一起,组成为一个数,则这个数是最小的。
输入格式
一行一个整数N
输出格式
一个N*N的拉丁方阵,
输入输出示例:
输入
3
输出
1 2 3
2 3 1
3 1 2
输入
5
输出
1 2 3 4 5
2 1 4 5 3
3 4 5 1 2
4 5 2 3 1
5 3 1 2 4
问题分析:
枚举每一个格子可能放的数,搜索深度为n*n,搜索宽度为n,设置两个二维的布尔数组b[i,j]和c[i,j],记录行和列中出现过的数字,b[i,j]=true表示第i行的数j可以使用,c[i,j]=true表示第i列的数j可以使用。用数组a[i,j]记录结果,由于采用了二维数组记录结果,所以在枚举n*n个格子的时候需要把一维数组转成二维。
搜索算法_找零钱
AYYZOJ p1454
问题描述:
有2n个人排队购一件价为0.5元的商品,其中一半人拿一张1元人民币,另一半人拿一张0.5元的人民币,要使售货员在售货中,不发生找钱困难,问这2n个人应该如何排队?找出所有排队的方案。(售货员一开始就没有准备零钱)
输入:
输入文件money.in仅一个数据n
输出:
输出文件money.out若干行,每行一种排队方案,每种方案前加序号No.i,每种方案0表示持0.5元钞票的人,1表示持1元钞票的人
样例:
money.in
3
money.out
NO.1:000111
No.2:001011
No.3:001101
No.4:010011
No.5:010101
问题分析:
1、 结束状态定义:用一维数组b[k]记录排队状态,b[k]=0表示拿0.5元的,b[k]=1表示拿1元的,每一步的结点状态转换到下一状态,直接转换即可,即b[k]=i(i=0或1)。另外用数组d记录当前状态下0的个数d[0]和1的个数d[1]
2、 搜索宽度:因为每个人手中的钞票不是0.5元就是1元,只有两种情况,所以搜索宽度为2
3、 子结点扩展条件:当前结点向下扩展,需满足的条件是,前面所有人手持的0.5元的个数要大于等于1元的个数,并且0.5元的个数要小于等于n
4、 目标结点状态:前k个人已经排好队,即k>2*n,并且d[0]=d[1]
恢复递归前的状态:由于使用了全局变量数组d,当在递归前改变d[i]的值时,即inc(d[i]),递归后要恢复d[i]的值,即dec(d[i])。
后两题程序见搜索与回溯算法(三)
AYYZOJ p1418
COGS p1105
【问题描述】
有一个m*n格的迷宫(表示有m行、n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这m*n个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-l表示无路)。
【输入】
第一行是两个数m,n(1<m,n<15),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。
【输出】
所有可行的路径,描述一个点时用(x,y)的形式,除开始点外,其他的都要用“->”表示方向。
如果没有一条可行的路则输出-1。
【样例】
maze.in
5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6
maze.out
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
【样例解释】:由于搜索时试探的顺序不一样,路线方案也就不同,输出样例中试探方向是按左、上、右、下的顺序试探的,编程时请按此顺序试探,否则可能结果与标准数据输出不一致。
【算法分析】
用一个a数组来存放迷宫可走的情况,另外用一个数组b来存放哪些点走过了。每个点用两个数字来描述,一个表示行号,另一个表示列号。对于某一个点(x,y),四个可能走的方向的点描述如下表:
1 | ||
4 | x,y | 2 |
3 |
注意:参考程序中的遍历顺序是左上右下,cogs中遍历顺序是上左右下。
const x1:array[1..4] of integer=(0,-1,0,1); y1:array[1..4] of integer=(-1,0,1,0); maxnm=15; var n,m,x,y,i,j,maxm,maxn,xx,yy: byte; g,b:array[0..maxnm,0..maxnm] of 0..1; t:array[1..maxnm*maxnm,1..2] of integer; total:longint; procedure print; var i:integer; begin write('(',t[1,1],',',t[1,2],')'); for i:=2 to j do write('->(':2,t[i,1],',',t[i,2],')'); writeln; end; procedure sol(x,y:integer); var i,xx,yy:integer; begin for i:=1 to 4 do begin if (x+x1[i]>=1) and (x+x1[i]<=maxm) and (y+y1[i]>=1) and (y+y1[i]<=maxn) and (g[x+x1[i],y+y1[i]]=1) and (b[x+x1[i],y+y1[i]]=0) then begin xx:=x+x1[i];yy:=y+y1[i]; inc(j); t[j,1]:=xx; t[j,2]:=yy; b[xx,yy]:=1; if (xx=m) and (yy=n) then begin inc(total); print;end else sol(xx,yy); b[xx,yy]:=0; dec(j); end; end; end; begin readln(maxm,maxn); for i:=1 to maxm do begin for j:=1 to maxn do read(g[i,j]); readln; end; readln(x,y); readln(m,n); total:=0;j:=1;t[1,1]:=x;t[1,2]:=y; b[x,y]:=1; sol(x,y); if total=0 then writeln('-1'); end.
参考程序
搜索算法_最小拉丁方阵
AYYZOJ p1453
问题描述:
输入 N,求 N 阶最小的拉丁方阵 (2 ≤ N ≤ 9)。N 阶拉丁方阵为每一行、每一列都是数字1到N,且每个数字只出现一次。最小拉丁方阵是将方阵的一行一行数连接在一起,组成为一个数,则这个数是最小的。
输入格式
一行一个整数N
输出格式
一个N*N的拉丁方阵,
输入输出示例:
输入
3
输出
1 2 3
2 3 1
3 1 2
输入
5
输出
1 2 3 4 5
2 1 4 5 3
3 4 5 1 2
4 5 2 3 1
5 3 1 2 4
问题分析:
枚举每一个格子可能放的数,搜索深度为n*n,搜索宽度为n,设置两个二维的布尔数组b[i,j]和c[i,j],记录行和列中出现过的数字,b[i,j]=true表示第i行的数j可以使用,c[i,j]=true表示第i列的数j可以使用。用数组a[i,j]记录结果,由于采用了二维数组记录结果,所以在枚举n*n个格子的时候需要把一维数组转成二维。
搜索算法_找零钱
AYYZOJ p1454
问题描述:
有2n个人排队购一件价为0.5元的商品,其中一半人拿一张1元人民币,另一半人拿一张0.5元的人民币,要使售货员在售货中,不发生找钱困难,问这2n个人应该如何排队?找出所有排队的方案。(售货员一开始就没有准备零钱)
输入:
输入文件money.in仅一个数据n
输出:
输出文件money.out若干行,每行一种排队方案,每种方案前加序号No.i,每种方案0表示持0.5元钞票的人,1表示持1元钞票的人
样例:
money.in
3
money.out
NO.1:000111
No.2:001011
No.3:001101
No.4:010011
No.5:010101
问题分析:
1、 结束状态定义:用一维数组b[k]记录排队状态,b[k]=0表示拿0.5元的,b[k]=1表示拿1元的,每一步的结点状态转换到下一状态,直接转换即可,即b[k]=i(i=0或1)。另外用数组d记录当前状态下0的个数d[0]和1的个数d[1]
2、 搜索宽度:因为每个人手中的钞票不是0.5元就是1元,只有两种情况,所以搜索宽度为2
3、 子结点扩展条件:当前结点向下扩展,需满足的条件是,前面所有人手持的0.5元的个数要大于等于1元的个数,并且0.5元的个数要小于等于n
4、 目标结点状态:前k个人已经排好队,即k>2*n,并且d[0]=d[1]
恢复递归前的状态:由于使用了全局变量数组d,当在递归前改变d[i]的值时,即inc(d[i]),递归后要恢复d[i]的值,即dec(d[i])。
后两题程序见搜索与回溯算法(三)
相关文章推荐
- 第三百零六天 how can I 坚持
- CDOJ 1271 Search gold
- 网络流 最大流 ISAP算法
- java数据库编程——执行SQL 语句
- 331. Verify Preorder Serialization of a Binary Tree
- 网络流 ISAP算法
- 军旅风电商崛起:砺剑户外用品深度调查
- CodeForces 543B Destroying Roads(最短路BFS)
- ruby include和exclude区别
- 搜索与回溯算法(二)
- CDOJ 1269 ZhangYu Speech
- 1003. 我要通过!(20)
- Fragment使用(二)
- Kinect视觉SLAM技术介绍
- 【DP】Codeforces Round #341 (Div. 2) E
- 动态调用DLL时不能加载依赖的程序集
- 第二章实例:ArrayAdapter结合ListView列表视图
- CDOJ 1272 Final Pan's prime numbers
- 【差分约束】BZOJ 2330: [SCOI2011]糖果
- [转]FastJSON通过SerializeFilter定制序列化