青蛙跳跃的最后一个变体显示在the video的末尾。
简而言之,你有一个系列中的 n 数量的百合花垫和一只青蛙 每一个。
在最后一个变体(我想要暴力),第二个 第一个和第二个睡莲垫没有青蛙。你的目标是 把所有青蛙都放到同一个睡莲垫上。每只青蛙都可以向右或向左跳 根据其百合垫上的青蛙数量,但不能跳上一个 空百合垫。
(带1只青蛙的垫子移动1个点,带有n个青蛙的垫子移动仅 n个点)n = 12的解的例子:( 12以下没有解)
[1,0,1,1,1,1,1,1,1,1,0,1] - 开始形成青蛙。 (数数 青蛙从0到11.)
[1,0,1,0,2,1,1,1,1,1,0,1] - 青蛙3.跳跃 右一[1,0,1,0,2,1,2,0,1,1,0,1] - 青蛙7.向左跳 [1,0,1,0,4,1,0,0,1,1,0,1] - 青蛙6.跳左 [5,0,1,0,0,1,0,0,1,1,0,1] - 青蛙4.向左跳 [0,0,1,0,0,6,0,0,1,1,0,1] - 青蛙0.跳到右边 [0,0,1,0,0,0,0,0,1,1,0,7] - 青蛙5.跳到右边 [0,0,1,0,0,0,0,0,0,2,0,7] - 青蛙8.跳到右边 [0,0,1,0,0,0,0,0,0,0,0,9] - 青蛙9.跳到右边 [0,0,10,0,0,0,0,0,0,0,0,0] - 青蛙11.跳左 - 解决了
如果解决方案存在,我想找到n个青蛙的解决方案。我手工知道12,14,15,16,17,18,19,20至少有一个解决方案, 1-11和13没有解决方案。
我尝试编写一段代码,通过所有组合来找到 n 百合花垫的解决方案。
编辑:由于OleV.V.,代码现在可以正常运行,还添加了日志记录。
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
// # Brute Force # Brute Force # Brute Force # Brute Force # Brute Force # //
public class Frogger {
/**
* PUBLIC STATIC GLOBAL VARIABLES - Modify these as you wish.
*
* Time Data: Levels < 20 ~ around couple seconds
* Level = 20 ~ around a minute
* Level = 21 ~ around a quarter of an hour
* Level = 22 ~ around a sixth of a minute
* Level = 23 ~ around half an hour
* Level = 24 ~ around a minute
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
public static int Level = 12;
public static boolean LogSolution = true;
public static boolean LogAll = false;
/** * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// used for logging
private static Deque<Jump> solution = new ArrayDeque<>(Level);
private static double time;
public static void main(String[] args) {
// log the time
time = System.currentTimeMillis();
// build the world & start jumping
run(Level);
}
public static void run(int n) {
// create the world
int[] world = new int[n];
for (int i = 0; i < n; i++) {
world[i] = 1;
}
world[1] = 0;
world[n-2] = 0;
// start jumping
if (Level > 11 && Level != 13) jump(world);
else System.out.println("Unsolvable");
}
//////////////////////////////////////////////////////
public static void jump(int[] world) {
for (int i = 0; i < world.length; i++) {
if (world[i] != 0) { // pad has a frog
// check if it is solved at current pad
if (world[i] == Level - 2) {
System.out.println("SOLUTION: " + Arrays.toString(world));
System.out.println(solution);
System.out.println("\n" + (System.currentTimeMillis() - time) / 1000 + " seconds");
System.exit(0);
}
// roll-back var
int temp = 0;
// attempts to make a RIGHT jump
if (world[i] + i < world.length) { // right jump is in bound
if (world[i + world[i]] != 0) { // can't jump on empty pad
temp = world[i];
// jump RIGHT
world[i + world[i]] += world[i];
world[i] = 0;
solution.push(new Jump(temp, i, i + temp)); // log the solution step 1/2
if (LogSolution) if (LogAll) System.out.println( "J: " + Arrays.toString(world)); // log the jump
// continue jumping
jump(world);
// roll-back right jump
world[i] = temp;
world[i + world[i]] -= world[i];
if (LogAll) System.out.println("R: " + Arrays.toString(world)); // log the rollback
if (LogSolution) solution.pop(); // log the solution step 2/2
}
}
// attempts to make a LEFT jump
if (i - world[i] >= 0) { // left jump is in bound
if (world[i - world[i]] != 0) { // can't jump on empty pad
temp = world[i];
// jump LEFT
world[i - world[i]] += world[i];
world[i] = 0;
if (LogSolution) solution.push(new Jump(temp, i, i - temp)); // log the solution step 1/2
if (LogAll) System.out.println("J:" + Arrays.toString(world)); // log the jump
// continue jumping
jump(world);
// roll-back left jump
world[i] = temp;
world[i - world[i]] -= world[i];
if (LogAll) System.out.println("R: " + Arrays.toString(world)); // log the rollback
if (LogSolution) solution.pop(); // log the solution step 2/2
}
}
}
}
}
}
旁注:此问题在所有可解决的 n (所有n> 11,除13之外,有一个解决方案,可通过广义方法访问)进行数学求解。这段代码只是我试图在java中做一些递归。
答案 0 :(得分:1)
首先,如何记录解决方案?我想你认为最终结果是[0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0]
并不是那么有趣;我们想知道它是如何获得的。我将介绍两种方式。
更简单的方法是在尝试时存储每个步骤,然后在回溯时删除它。然后,当您到达解决方案时,您还存储了导致它的步骤。使用堆栈或类似的东西:
private static Deque<Jump> solution = new ArrayDeque<>(Level);
(java.util.ArrayDeque
是堆栈和队列的推荐类;对于堆栈ArrayList
是另一种选择。)现在在代码中,log the jump
执行
solution.push(new Jump(temp, i, i + temp));
在log the rollback
做
solution.pop();
使用一个简单的辅助类Jump
,例如:{/ p>
public class Jump {
int count;
int from;
int to;
public Jump(int count, int from, int to) {
this.count = count;
this.from = from;
this.to = to;
}
@Override
public String toString() {
return "" + count + " frog/s jump from " + from + " to " + to;
}
}
当我在我的解决方案中尝试它时,一次搜索花了20%的时间。我说这是可以接受的。如果您非常关注性能,只需在找到解决方案后登出即可。这将要求您返回一个布尔值来表示成功,而不是使用System.exit()来停止搜索。现在您的递归调用变为:
if (jump(world)) {
solution.push(new Jump(temp, i, i + temp));
return true;
}
您获得解决方案堆栈中的元素的顺序与之前相反,我希望您能够解决这个问题。而不是System.exit(0);
做return true;
。在方法的底部,返回false。我没有测量性能影响,但我认为与没有记录任何东西相比,它只是微小的。现在您可以得到如下输出:
1 frog/s jump from 3 to 4
1 frog/s jump from 7 to 6
2 frog/s jump from 6 to 4
4 frog/s jump from 4 to 0
5 frog/s jump from 0 to 5
6 frog/s jump from 5 to 11
1 frog/s jump from 8 to 9
2 frog/s jump from 9 to 11
9 frog/s jump from 11 to 2
最后,这是我的方式,只是为了完整起见。我没有发现你的代码有任何有趣的差异。
public static void jump(int[] world) {
for (int fromIndex = 0; fromIndex < world.length; fromIndex++) { // index of pad to jump from
// any frog/s here?
int frogsJumping = world[fromIndex];
if (frogsJumping > 0) {
// try to jump left; frogsJumping frogs jump frogsJumping places
int targetIndex = fromIndex - frogsJumping;
if (targetIndex >= 0 && world[targetIndex] > 0) { // must not jump to empty pad
performJump(fromIndex, targetIndex, world, frogsJumping);
}
// try a right jump
targetIndex = fromIndex + frogsJumping;
if (targetIndex < world.length && world[targetIndex] > 0) {
performJump(fromIndex, targetIndex, world, frogsJumping);
}
}
}
}
private static void performJump(int fromIndex, int toIndex, int[] world, int frogsJumping) {
solution.push(new Jump(frogsJumping, fromIndex, toIndex));
world[fromIndex] = 0;
world[toIndex] += frogsJumping;
if (world[toIndex] == noOfFrogs) {
System.out.println("Solved: " + Arrays.toString(world));
System.exit(0);
}
jump(world);
// backtrack
world[toIndex] -= frogsJumping;
world[fromIndex] = frogsJumping;
solution.pop();
}