Решить n-головоломку на JavaJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Решить n-головоломку на Java

Сообщение Anonymous »

Я пытаюсь реализовать программу для решения задачи n-головоломок.

Я написал простую реализацию на Java, состояние которой характеризуется матрицей, представляющей плитки. Я также могу автоматически создать график всех состояний, дающих начальное состояние. Тогда на графе я могу выполнить BFS, чтобы найти путь к целевому состоянию.

Но проблема в том, что у меня заканчивается память, и я даже не могу создать весь граф.
Я попробовал с плитками 2x2, и это работает. Также с некоторыми 3x3 (это зависит от начального состояния и количества узлов в графе). Но в целом этот способ не подходит.

Поэтому я попробовал генерировать узлы во время выполнения во время поиска. Это работает, но медленно (иногда через несколько минут оно все еще не закончилось, и я закрываю программу).

Кстати: я даю в качестве стартового состояния только решаемые конфигурации и не создаю дублированные состояния .

Поэтому я не могу построить график. Это приводит к моей основной проблеме: мне нужно реализовать алгоритм A*, и мне нужна стоимость пути (т. е. для каждого узла расстояние от начального состояния), но я думаю, что не могу вычислить его во время выполнения. Мне нужен весь график, верно? Поскольку A* не следует исследованию графа BFS, поэтому я не знаю, как оценить расстояние для каждого узла. Следовательно, я не знаю, как выполнить поиск A*.

Есть предложения?

ИЗМЕНИТЬ

Код: Выделить всё

private int[][] tiles;
private int pathDistance;
private int misplacedTiles;
private State parent;

public State(int[][] tiles) {
this.tiles = tiles;
pathDistance = 0;
misplacedTiles = estimateHammingDistance();
parent = null;
}

public ArrayList findNext() {
ArrayList next = new ArrayList();
int[] coordZero = findCoordinates(0);
int[][] copy;
if(coordZero[1] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] + 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[1] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] - 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0] + 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0] - 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
return next;
}

private State checkNewState(int[][] tiles) {
State newState = new State(tiles);
for(State s : Solver.states)
if(s.equals(newState))
return null;
return newState;
}

@Override
public boolean equals(Object obj) {
if(this == null || obj == null)
return false;
if (obj.getClass().equals(this.getClass())) {
for(int r = 0; r < tiles.length; r++) {
for(int c = 0; c < tiles[r].length; c++) {
if (((State)obj).getTiles()[r][c] != tiles[r][c])
return false;
}
}
return true;
}
return false;
}

Код: Выделить всё

public static final HashSet states = new HashSet();

public static void main(String[] args) {
solve(new State(selectStartingBoard()));
}

public static State solve(State initialState) {
TreeSet queue = new TreeSet(new Comparator1());
queue.add(initialState);
states.add(initialState);
while(!queue.isEmpty()) {
State current = queue.pollFirst();
for(State s : current.findNext()) {
if(s.goalCheck()) {
s.setParent(current);
return s;
}
if(!states.contains(s)) {
s.setPathDistance(current.getPathDistance() + 1);
s.setParent(current);
states.add(s);
queue.add(s);
}
}
}
return null;
}
В основном вот что я делаю:

- Решение имеет SortedSet . Элементы () сортируются в соответствии с Comparator1, который вычисляет f(n) = g(n) + h(n), где g(n) — стоимость пути и h(n) — это эвристика (количество неуместных плиток).

- Даю стартовую конфигурацию и ищу всех преемников.

- Если преемник еще не посещался (т.е. если он не находится в глобальном наборе состояний) я добавляю его в очередь и в состояния, устанавливая текущее состояние в качестве его родителя и путь к родительскому элементу + 1< /code> в качестве стоимости пути.

- Извлеките из очереди и повторите.

Я думаю, это должно сработать, потому что:

- Я сохраняю все посещенные состояния, поэтому не зацикливаюсь.

- Кроме того, не будет никаких бесполезных ребер, потому что я сразу сохраняю преемников текущего узла. Например: если из A я могу пойти в B и C, а из B я также могу пойти в C, ребра B->C не будет (поскольку стоимость пути равна 1 для каждого ребра и A->B дешевле, чем A ->B->C).

- Каждый раз я выбираю расширение пути с минимальным f(n) в соответствии с A*.

Но это не работает. Или, по крайней мере, через несколько минут он все еще не может найти решение (и я думаю, что в этом случае это много времени).

Если я попытаюсь создать древовидную структуру перед выполнением A* мне не хватает памяти для его построения.

РЕДАКТИРОВАТЬ 2

Вот мои эвристические функции:

Код: Выделить всё

private int estimateManhattanDistance() {
int counter = 0;
int[] expectedCoord = new int[2];
int[] realCoord = new int[2];
for(int value = 1; value < Solver.SIZE * Solver.SIZE; value++) {
realCoord = findCoordinates(value);
expectedCoord[0] = (value - 1) / Solver.SIZE;
expectedCoord[1] = (value - 1) % Solver.SIZE;
counter += Math.abs(expectedCoord[0] - realCoord[0]) + Math.abs(expectedCoord[1] - realCoord[1]);
}
return counter;
}

private int estimateMisplacedTiles() {
int counter = 0;
int expectedTileValue = 1;
for(int i = 0; i < Solver.SIZE; i++)
for(int j = 0; j < Solver.SIZE; j++) {
if(tiles[i][j] != expectedTileValue)
if(expectedTileValue != Solver.ZERO)
counter++;
expectedTileValue++;
}
return counter;
}
Если я использую простой жадный алгоритм, они оба работают (использование Манхэттенского расстояния происходит очень быстро (около 500 итераций для поиска решения), а с учетом количества неуместных плиток это занимает около 10 тысяч итераций). Если я использую A* (оценивая также стоимость пути), это будет очень медленно.

Компараторы такие:

Код: Выделить всё

public int compare(State o1, State o2) {
if(o1.getPathDistance() + o1.getManhattanDistance() >= o2.getPathDistance() + o2.getManhattanDistance())
return 1;
else
return -1;
}
РЕДАКТИРОВАТЬ 3

Было небольшая ошибка. Я исправил это, и теперь A* работает. Или, по крайней мере, для 3x3 if находит оптимальное решение всего за 700 итераций. Для 4x4 это все еще слишком медленно. Я попробую с IDA*, но один вопрос: сколько времени понадобится с A*, чтобы найти решение? Минуты? Часы? Я оставил это на 10 минут, и это не закончилось.

Подробнее здесь: https://stackoverflow.com/questions/120 ... le-in-java
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Проблемы с подготовкой к экзамену по C++, не могу решить эту головоломку
    Anonymous » » в форуме C++
    0 Ответы
    13 Просмотры
    Последнее сообщение Anonymous
  • Как обойти капчу слайдера, чтобы решить головоломку с помощью селена? (Python)
    Anonymous » » в форуме Python
    0 Ответы
    18 Просмотры
    Последнее сообщение Anonymous
  • Необходимо решить головоломку ASCII в одной команде на Linux [закрыто]
    Anonymous » » в форуме Linux
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous
  • Как обойти слайдер Captcha, чтобы решить головоломку с помощью селена? (Python)
    Anonymous » » в форуме Python
    0 Ответы
    5 Просмотры
    Последнее сообщение Anonymous
  • Как создать головоломку судоку на Python
    Anonymous » » в форуме Python
    0 Ответы
    20 Просмотры
    Последнее сообщение Anonymous

Вернуться в «JAVA»