Грубая сила лягушка Прыжки игра
Последняя вариация прыжка лягушки показана в концевидео .
Короче говоря, у вас есть n количество лилий в строке и одна лягушка на каждый из них.В последнем варианте (тот, который я хочу перебить силой), второй первая и вторая последние лилии не имеют лягушки. Ваша цель состоит в том, чтобы соберите всех лягушек в одну Лилию. Каждая лягушка может прыгать вправо или влево основываясь на количестве лягушек на его лилии, но не может прыгать на пустой лилейник.
(площадку с 1 движется лягушка 1 место, коврик с 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,0,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,0,1,1,0,7] - лягушки 5. прыгнул вправо
[0,0,1,0,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,0] - лягушки 11. прыгнул влево-решил
Я хочу найти решения для n лягушек, если решение существует.Я знаю от руки, что 12,14,15,16,17,18,19,20 имеют по крайней мере одно решение и что 1-11 и 13 не имеют решения.
Я попытался написать фрагмент кода, который будет проходить через все комбинации, чтобы найти решение для n лилий.
EDIT: код теперь работает, благодаря 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.
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
dosolution.push(new Jump(temp, i, i + temp));
At
log the rollback
dosolution.pop();
Используйте простой вспомогательный класс
Jump
, который может, например, выглядеть следующим образом:Когда я попробовал его в своем решении, один поиск занял на 20 % больше времени. Я бы сказал, что это приемлемо. Если вы очень обеспокоены производительностью, просто войдите в свой путь из-за того, что нашел решение. Это потребует, чтобы вы возвратили логическое значение, чтобы указать успех, а не использовать System.exit () для остановки поиска. Теперь ваш рекурсивный вызов становится: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; } }
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(); }