UVA101 The Blocks Problem
题目描述

输入格式

输出格式

输入输出样例 #1
输入 #1
10
move 9 onto 1
move 8 over 1
move 7 over 1
move 6 over 1
pile 8 over 6
pile 8 over 5
move 2 over 1
move 4 over 9
quit
输出 #1
0: 0
1: 1 9 2 4
2:
3: 3
4:
5: 5 8 7 6
6:
7:
8:
9:
题目大意
计算机科学很多领域会使用简单抽象模型做理论和实验研究。比如早期人工智能的规划与机器人研究(STRIPS)就使用积木世界模型,机械臂完成积木搬运任务。
本题要模拟简单积木世界,遵循给定规则。不用自己寻找达到目标状态的方案,而是编写程序让机械臂按照一系列指令操作积木。
初始状态:桌上有n块积木,编号0 ~ n-1,依次并排摆在桌面上,每块单独占一个位置。
机械臂操作积木的合法指令如下:
- move a onto b
其中 a、b 为积木编号,先将堆积在积木 a 和积木 b 上方的所有积木放回各自初始位置,再把积木 a 放到积木 b 之上。 - move a over b
其中 a、b 为积木编号,先将堆积在积木 a 上方的所有积木放回各自初始位置,再把积木 a 放到包含积木 b 的那一堆积木的顶端。 - pile a onto b
其中 a、b 为积木编号,将由积木 a 以及堆叠在 a 上方的所有积木组成的整叠积木移动到积木 b 之上。执行堆叠操作前,需要先把积木 b 上方的所有积木放回各自初始位置。堆叠在 a 上方的积木在移动时保持原有上下顺序不变。 - pile a over b
其中 a、b 为积木编号,将由积木 a 以及堆叠在 a 上方的所有积木组成的整叠积木,放到包含积木 b 的那一堆积木的顶端。堆叠在 a 上方的积木在移动时保持原有上下顺序不变。 - quit
终止积木世界的所有操作。
如果一条指令满足 a 等于 b,或者 a 与 b 原本就在同一堆积木中,则该指令为非法指令。所有非法指令都应当被忽略,不会对积木的摆放状态产生任何影响。
输入
第一行单独一个整数n,代表积木总数,0<n<25。之后每行一条指令,直到读到quit停止。保证所有指令语法正确。
输出
输出积木世界的最终状态。一共输出n行,对应原始位置0,1,...,n-1每行格式:位置号,冒号后面如果有积木,先加空格,接着输出这一堆积木编号,空格分隔,不能行尾多余空格;如果该位置没有积木,就只输出位置号。
解题思路
用一个二维列表保存每一堆积木,另外开一个数组记录每一块积木当前在哪一堆,用来快速查询位置,避免每次遍历查找。程序先读取积木总数,初始化状态,每块积木一开始单独占一堆。接着循环读取每一条指令,读到 quit 就停止输入。处理指令时先判断是否非法,a 等于 b 或者两块积木本来就在同一堆就直接跳过这条指令。如果指令里是 onto,就先把 b 上方所有积木放回各自初始位置;如果是 move 操作,就把 a 上方所有积木放回初始位置,再单独移动 a;如果是 pile 操作,就把 a 以及 a 上方的一整叠积木完整移过去,保持积木之间的上下顺序。移动积木时同步更新位置数组。全部指令处理完成后,按堆号从小到大输出每一堆里的积木。
完整代码
java
import java.util.*;
public class TheBlocksProblem {
private static List<List<Integer>> world;
private static int[] positionOf;
private static int n;
private static List<String[]> readInput(Scanner scanner) {
n = Integer.parseInt(scanner.nextLine().trim());
initWorld(n);
List<String[]> commands = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (line.isEmpty()) continue;
String[] tokens = line.split("\\s+");
if (tokens[0].equals("quit")) {
break;
}
commands.add(tokens);
}
return commands;
}
private static void initWorld(int n) {
world = new ArrayList<>();
positionOf = new int[n];
for (int i = 0; i < n; i++) {
List<Integer> pile = new ArrayList<>();
pile.add(i);
world.add(pile);
positionOf[i] = i;
}
}
private static void processCommands(List<String[]> commands) {
for (String[] cmd : commands) {
String action = cmd[0];
int a = Integer.parseInt(cmd[1]);
String prep = cmd[2];
int b = Integer.parseInt(cmd[3]);
if (a == b || positionOf[a] == positionOf[b]) {
continue;
}
if (prep.equals("onto")) {
returnAbove(b);
}
if (action.equals("move")) {
returnAbove(a);
moveBlock(a, b);
} else { // "pile"
movePile(a, b);
}
}
}
private static void returnAbove(int block) {
int pos = positionOf[block];
List<Integer> pile = world.get(pos);
int idx = pile.indexOf(block);
for (int i = pile.size() - 1; i > idx; i--) {
int topBlock = pile.remove(i);
returnToInitial(topBlock);
}
}
private static void returnToInitial(int block) {
int initPos = block;
positionOf[block] = initPos;
world.get(initPos).add(block);
}
private static void moveBlock(int a, int b) {
int posA = positionOf[a];
int posB = positionOf[b];
world.get(posA).remove(Integer.valueOf(a));
world.get(posB).add(a);
positionOf[a] = posB;
}
private static void movePile(int a, int b) {
int posA = positionOf[a];
int posB = positionOf[b];
List<Integer> pileA = world.get(posA);
int idx = pileA.indexOf(a);
List<Integer> movingBlocks = new ArrayList<>(pileA.subList(idx, pileA.size()));
pileA.subList(idx, pileA.size()).clear();
for (int block : movingBlocks) {
world.get(posB).add(block);
positionOf[block] = posB;
}
}
private static void printResult() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.append(i).append(":");
List<Integer> pile = world.get(i);
for (int block : pile) {
sb.append(" ").append(block);
}
sb.append("\n");
}
System.out.print(sb);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<String[]> commands = readInput(sc);
processCommands(commands);
printResult();
sc.close();
}
}
测评结果
