Ошибка поиска первой глубины - PullRequest
1 голос
/ 05 декабря 2011

Я работаю над заданием по программированию (в Java), чтобы решить вещь из пятнадцати загадок . Первая часть - использовать поиск в глубину, чтобы найти решение. Я хочу, чтобы он мог решить сколь угодно большую загадку, чтобы весь граф пространства состояний не умещался в памяти. Вместо этого алгоритм будет хранить список исследованных состояний, чтобы проверить будущие состояния. Алгоритм выглядит примерно так:

Если мы находимся в состоянии цели, значит, мы закончили.
Если нет, то для каждого соседа, которого нет в исследуемом списке, добавьте его в исследуемый список и сначала выполните рекурсивный поиск в глубине.

Однако, это не работает должным образом. Я провел несколько тестов и считаю, что проблема в том, что когда я вставляю состояние в исследуемый список, он фактически вставляет тот же объект , так что когда я изменяю состояние позже, исследуемый список также изменяется. Из-за этого программе никогда не кажется, что состояние не было исследовано.

Я попытался написать метод для копирования состояний и передачи копии в исследуемый список; но та же проблема сохраняется. Однако, когда я протестировал метод копирования независимо, он, кажется, успешно копирует состояния. Я полностью сбит с толку относительно того, в чем проблема.

Здесь задействовано много кода, и я не уверен, в чем проблема, но вот код для поиска в глубину:

this class we're in is the puzzle class, and this is the depth first search
'state' keeps track of the current state we're in
'explored' is a linked list of explored states

public String depthFirst(){
    state.clearPath();            // state keeps track of the path taken
    explored = new LLNode(state); // create explored list with starting state
    this.dfs();                   // depth first search
    return state.path();
}

private boolean dfs(){
    if(state.equals(goal))        // if we're in the goal state, then done
        return true;
    char[] directions = {'n', 'e', 's', 'w'};
    for(char dir : directions){   // otherwise, for each direction
        if(state.move(dir)){      // if we can move in that direction, then do
            if(!explored.contains(state)){  // if the new state is unexplored
                explored = explored.insert(state.copy());
                if(this.dfs())              // add it to explored and recurse
                    return true;
            }
            switch(dir){                    // if search failed, move back and
                                            // search the next direction
                case 'n': state.move('s');
                case 'e': state.move('w');
                case 's': state.move('n');
                case 'w': state.move('e');
            }
        }
    }
    return false;  // indicates failure
}

Вот вставка и содержит методы для explored:

public LLNode insert(Node gameState){
    if(state == null){        // if this list node doesn't have a state
        state = gameState;    // then give it this one
        return this;
    }                         // otherwise tack it on the front of the list
    return new LLNode(gameState, this);  // and return the new head
}

public boolean contains(Node gameState){
    // I had a test here that printed a message if (state == gameState)
    // which was triggered when I ran the program, suggesting the problem
    // I explained above
    if(state.equals(gameState))
        return true;
    else if(next == null)
        return false;
    else
        return next.contains(gameState);
}

Вот функция копирования для класса Node

public Node copy(){
    int[][] newState = new int[state.length][state[0].length];
    for(int i = 0; i < state.length; ++i)
        for(int j = 0; j < state[0].length; ++j)
            newState[i][j] = state[i][j];
    return new Node(newState);
}

Спасибо за любые идеи!

Ответы [ 2 ]

1 голос
/ 05 декабря 2011

Я бы проверил, что state.move() вообще не ссылается на explored - глядя на предоставленный код, это единственное место, где я могу представить, что ваши переменные могут ссылаться на те же массивы.

Требовалось ли присвоение для прокрутки ваших собственных структур данных (т. Е. Связанного списка)? Если нет, то я бы выбрал стандартную Java HashSet (или любую другую, которая лучше всего соответствует вашим требованиям), поскольку я не вижу необходимости помнить порядок поиска, только тот факт, что вы уже исследовали определенное состояние.

Кроме того, необходимо ли хранить весь массив для каждого исследуемого состояния? Возможно, было бы лучше (потреблять меньше памяти и, как правило, более эффективно) просто запомнить хеш для каждого исследуемого состояния (которое можно сохранить в HashSet).

Примечание: Ваш метод copy() предполагает массив NxN (что хорошо для вашего примера, но не сработало бы, если бы головоломка была прямоугольной).

0 голосов
/ 05 декабря 2011

вы знаете, что 16!равно 20 922 789 888 000 - ваша таблица исследованных состояний никоим образом не сработает, если вы не сделаете что-то еще, чтобы ограничить область поиска.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...