7.8 训练参考
前面已经提到过,本章介绍的算法比较有系统性,因此也没有选择太多的例题。建议读者独立完成所有例题。本章例题列表及说明如表7-3所示。
表7-3 例题列表
| 类别 | 题号 | 题目名称(英文) | 备注 |
| 例题7-1 | UVa725 | Division | 选择合适的枚举对象 |
| 例题7-2 | UVa11059 | Maximum Product | 枚举连续子序列 |
| 例题7-3 | UVa10976 | Fractions Again?! | 缩小枚举范围 |
| 例题7-4 | UVa524 | Prime Ring Problem | 回溯法和生成-测试法的比较 |
| 例题7-5 | UVa129 | Krypton Factor | 回溯法;避免无用判断 |
| 例题7-6 | UVa140 | Bandwidth | 回溯法;最优性剪枝 |
| 例题7-7 | UVa1354 | Mobile Computing | 回溯法;枚举二叉树 |
| 例题7-8 | UVa10603 | Fill | 状态图,Dijkstra算法 |
| 例题7-9 | UVa1601 | The Morning after Halloween | 路径寻找问题的“试验田” |
| 例题7-10 | UVa11212 | Editing a Book | IDA* |
| 例题7-11 | UVa12325 | Zombie's Treasure Chest | 两种枚举法 |
| 例题7-12 | UVa1343 | The Rotation Game | 状态空间分析 |
| 例题7-13 | UVa1374 | Power Calculus | IDA*,各种优化 |
| 例题7-14 | UVa1602 | Lattice Animals | 经典问题:生成n连块 |
| 例题7-15 | UVa1603 | Square Destroyer | 搜索对象及优化 |
下面是本章的习题。这些题目大都具有一定的复杂性,读者可以选择自己有兴趣的5道题目完成。如果想达到更好的效果,建议完成至少10道题目。
习题7-1 消防车(Firetruck, ACM/ICPC World Finals 1991, UVa208)
输入一个n(n≤20)个结点的无向图以及某个结点k,按照字典序从小到大顺序输出从结点1到结点k的所有路径,要求结点不能重复经过。
提示:要事先判断结点1是否可以到达结点k,否则会超时。
习题7-2 黄金图形(Golygons, ACM/ICPC World Finals 1993, UVa225)
平面上有k个障碍点。从(0,0)点出发,第一次走1个单位,第二次走2个单位,……,第n次走n个单位,恰好回到(0,0)。要求只能沿着东南西北方向走,且每次必须转弯90°(不能沿着同一个方向继续走,也不能后退)。走出的图形可以自交,但不能经过障碍点,如图7-25所示。
图7-25 黄金图形示意图
输入n、k(1≤n≤20,0≤k≤50)和所有障碍点的坐标,输出所有满足要求的移动序列(用news表示北、东、西、南),按照字典序从小到大排列,最后输出移动序列的总数。
习题7-3 多米诺效应(The Domino Effect, ACM/ICPC World Finals 1991, UVa211)
一副“双六”多米诺骨牌包含28张,编号如图7-26所示。
图7-26 多米诺骨牌编号
在7*8网格中每张牌各摆一张,如图7-27所示,左边是各个格子的点数,右边是各个格子所属的骨牌编号。
图7-27 7*8网格中骨牌摆放
输入左图,你的任务是输出所有可能的右图。
习题7-4 切断圆环链(Cutting Chains, ACM/ICPC World Finals 2000, UVa818)
有n(n≤15)个圆环,其中有一些已经扣在了一起。现在需要打开尽量少的圆环,使得所有圆环可以组成一条链(当然,所有打开的圆环最后都要再次闭合)。例如,有5个圆环,1-2, 2-3, 4-5,则需要打开一个圆环,如圆环4,然后用它穿过圆环3和圆环5后再次闭合圆环4,就可以形成一条链:1-2-3-4-5。
习题7-5 流水线调度(Pipeline Scheduling, UVa690)
你有一台包含5个工作单元的计算机,还有10个完全相同的程序需要执行。每个程序需要n(n<20)个时间片来执行,可以用一个5行n列的保留表(reservation table)来表示,其中每行代表一个工作单元(unit0~unit4),每列代表一个时间片,行i列j的字符为X表示“在程序执行的第j个时间片中需要工作单元i”。例如,如图7-28(a)所示就是一张保留表,其中程序在执行的第0, 1, 2, ……个时间片中分别需要unit0, unit1, unit2……
同一个工作单元不能同时执行多个程序,因此若两个程序分别从时间片0和1开始执行,则在时间片5时会发生冲突(两个程序都想使用unit0),如图7-28(b)所示。
输入一个5行n(n<20)列的保留表,输出所有10个程序执行完毕所需的最少时间。例如,对于图7-28(a)的保留表,执行完10个程序最少需要34个时间片。
| ![]() |
| (a) | (b) |
图7-28 流水线调度示意图
习题7-6 重叠的正方形(Overlapping Squares, Xia'an 2006, UVa12113)
给定一个4*4的棋盘和棋盘上所呈现出来的纸张边缘,如图7-29所示,问用不超过6张2*2的纸能否摆出这样的形状。
图7-29 重叠正方形示意图
习题7-7 埃及分数(Eg[y]ptian Fractions (HARD version), Rujia Liu's Present 6, UVa 12558)
把a/b写成不同的埃及分数之和,要求项数尽量小,在此前提下最小的分数尽量大,然后第二小的分数尽量大……另外有k(0≤k≤5)个数不能用作分母。例如,k=0时5/121=1/33+1/121+1/363,不能使用33时最优解为5/121=1/45+1/55+1/1089。
输入保证2≤a<b≤876,gcd(a,b)=1,且会挑选比较容易求解的数据。
习题7-8 数字谜(Digit Puzzle, ACM/ICPC Xi'an 2006,UVa12107)
给出一个数字谜,要求修改尽量少的数,使修改后的数字谜只有唯一解。例如,如图7-30所示的两个数字谜就有唯一解。
图7-30 数字谜示意图
修改指的是空格和数字可以随意替换,但不能增删。即空格换数字、数字换空格或数字替换。数字谜中所有涉及的数必须是没有前导零的正数。输入数字谜一定形如a*b=c,其中a、b、c分别最多有2、2、4位。
输入保证有解。如果有多种修改方案,则输出字典序最小的。字典序中空格小于数字。
习题7-9 立体八数码问题(Cubic Eight-Puzzle , ACM/ICPC Japan 2006, UVa1604)
有8个立方体,按照相同方式着色(如图7-31(a)所示,相对的面总是着相同颜色),然后以相同的朝向摆成一个3*3的方阵,空出一个位置(如图7-31(b)所示,空位由输入决定)。
| ![]() |
| (a) | (b) |
图7-31 立体八数码问题示意图
每次可以把一个立方体“滚动”一格进入空位,使它原来的位置成为空位,如图7-32所示。
图7-32 “滚动”后效果
你的任务是用最少的移动使得上表面呈现出指定的图案。输入空位的坐标和目标状态中上表面各个位置的颜色,输出最小移动步数。
习题7-10 守卫棋盘(Guarding the Chessboard, UVa11214)
输入一个n*m棋盘(n,m<10),某些格子有标记。用最少的皇后守卫(即占据或者攻击)所有带标记的格子。
习题7-11 树上的机器人规划(简单版)(Planning mobile robot on Tree (EASY Version), UVa12569)
有一棵n(4≤n≤15)个结点的树,其中一个结点有一个机器人,还有一些结点有石头。每步可以把一个机器人或者石头移到一个相邻结点。任何情况下一个结点里不能有两个东西(石头或者机器人)。输入每个石头的位置和机器人的起点和终点,求最小步数的方案。如果有多解,可以输出任意解。如图7-33所示,s=1,t=5时,最少需要16步:机器人1-6,石头2-1-7,机器人6-1-2-8,石头3-2-1-6,石头4-3-2-1,最后机器人8-2-3-4-5。
习题7-12 移动小球(Moving Pegs, ACM/ICPC Taejon 2000, UVa1533)
如图7-34所示,一共有15个洞,其中一个空着,剩下的洞里各有一个小球。每次可以让一个小球越过同一条直线上的一个或多个连续的小球,落到最近的空洞(不能越过空洞),然后拿走被跳过的小球。例如,让14跳到空洞5中,则洞9里的小球会被拿走,因此操作之后洞9和14会变空,而5里面会有一个小球。你的任务是用最少的步数让整个棋盘只剩下一个小球,并且位于初始时的那个空洞中。
| ![]() |
| 图7-33 树上的机器人规划示意图 | 图7-34 移动小球示意图 |
输入仅包含一个整数,即空洞编号,输出最短序列的长度m,然后是m个整数对,分别表示每次跳跃的小球所在的洞编号以及目标洞的编号。
习题7-13 数字表达式(According to Bartjens, ACM/ICPC World Finals 2000, UVa 817)
输入一个以等号结尾、前面只包含数字的表达式,插入一些加号、减号和乘号,使得运算结果等于2000。表达式里的整数不能有前导零(例如,0100或者000都是非法的),运算符都是二元的(例如,2*-100*-10+0=是非法的),并且符合通常的运算优先级法则。
输入数字个数不超过9。如果有多解,按照字典序从小到大输出;如果无解,输出IMPOSSIBLE。例如,2100100=有3组解,按照字典序依次为2*100*10+0=、2*100*10-0=和2100-100=。
习题7-14 小木棍(Sticks, ACM/ICPC CERC 1995, UVa 307)
乔治有一些同样长的小木棍,他把这些木棍随意地砍成几段,直到每段的长度都不超过50。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己最开始时有多少根木棍和它们的分别长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。例如,若砍完后有4根,长度分别为1, 2, 3, 4,则原来可能是2根长度为5的木棍,也可能是1根长度为10的木棍,其中5是最小可能长度。另一个例子是:砍之后的木棍有9根,长度分别为5, 2, 1, 5, 2, 1, 5, 2, 1,则最小可能长度为6(5+1=5+1=5+1=2+2+2=6),而不是8(5+2+1=8)。
习题7-15 最大的数(Biggest Number, UVa11882)
在一个R行C列(2≤R,C≤15,R*C≤30)的矩阵里有障碍物和数字格(包含1~9的数字)。你可以从任意一个数字格出发,每次沿着上下左右之一的方向走一格,但不能走到障碍格中,也不能重复经过一个数字格,然后把沿途经过的所有数字连起来,如图7-35所示。
如图7-35可以得到9784、4832145等整数。问:能得到的最大整数是多少?
习题7-16 找座位(Finding Seats Again, UVa11846)
有一个n*n(n<20)的座位矩阵里坐着k(k≤26)个研究小组。每个小组的座位都是矩形形状。输入每个小组组长的位置和该组的成员个数,找到一种可能的座位方案。如图7-36所示是一组输入和对应的输出。
| ![]() |
| 图7-35 最大的数示意图 | 图7-36 找座位问题示意图 |
习题7-17 Gokigen Naname谜题(Gokigen Naname, UVa11694)
在一个n*n(n≤7)网格中,有些交叉点上有数字。你的任务是给每个格子画一条斜线(一共只有“\”和“/”两种),使得每个交叉点的数字等于和它相连的斜线条数,且这些斜线不会构成环,如图7-37所示。
| ![]() |
图7-37 Gokigen Naname谜题示意图
习题7-18 推门游戏(The Wall Pusher, UVa10384)
如图7-38所示,从S处出发,每次可以往东、南、西、北4个方向之一前进。如果前方有墙壁,游戏者可以把墙壁往前推一格。如果有两堵或者多堵连续的墙,则不能推动。另外,游戏者也不能推动游戏区域边界上的墙。
图7-38 推门游戏示意图
用最少的步数走出迷宫(边界处没有墙的地方就是出口)。迷宫总是有4行6列,多解时任意输出一个移动序列即可(用NEWS这4字符表示移动方向)。
————————————————————
(1) 如果有读者找到反例或者正确性证明,请联系笔者或者出版社,我们会在重印时更正。
(2) 还有一个不错的候选算法是A*,可惜超出了本书的范围,有兴趣的读者可以自行搜索相关资料。
(3) 此处故意没有用前面介绍的h(s)、g(s)等记号。事实上,经常采用这种直观的方式来思考,而不去理会那些记号。
(4) 这个术语多用在传统人工智能书籍中,虽有一些描述上的差别,但本质相同。
(5) 一般来说,状态总数不超过106时都在可接受范围内。不过这只是一般规律,还要具体问题具体分析。
(6) 这种技巧称为结点排序(node ordering)。
(7) 可以参考en.wikipedia.org/wiki/Polyomino。