Как правильно проверить доступный путь на лабиринте [дубликат]

Чтобы привязываться к модели на обратной стороне, атрибуты name элементов управления формы должны соответствовать свойствам модели. Использование цикла foreach не создает правильные атрибуты имени. Если вы проверите html, вы увидите несколько экземпляров

<input type="text" name="item.LeaveType" .../>

, но для привязки к вашей модели элементы управления должны быть

<input type="text" name="LeaveDetailsList[0].LeaveType" .../>
<input type="text" name="LeaveDetailsList[1].LeaveType" .../>

и т. Д. Самый простой способ подумать об этом - рассмотреть вопрос о том, как вы получите доступ к значению свойства LeaveType в коде C#

var model = new LeaveBalanceViewModel();
// add some LeaveBalanceDetails instances to the LeaveDetailsList property, then access a value
var leaveType = model.LeaveDetailsList[0].LeaveType;

. Поскольку ваш метод POST будет иметь имя параметра (скажем, model), просто снимите префикс (model), и именно так должен быть атрибут имени элемента управления. Для этого вы должны использовать либо цикл for (сбор должен реализовывать IList<T>)

for(int i = 0; i < Model.LeaveDetailsList.Count; i++)
{
    @Html.TextBoxFor(m => m.LeaveDetailsList[i].LeaveType)
    ....
}

, либо использовать пользовательский EditorTemplate (в коллекции необходимо реализовать только IEnumerable<T>)

В /Views/Shared/EditorTemplates/LeaveBalanceDetails.cshtml

@model yourAssembly.LeaveBalanceDetails
<tr>
    <td>@Html.TextBoxFor(m => m.LeaveType)</td>
    ....
</tr>

, а затем в основном представлении (не в цикле)

<table>
    .... // add headings (preferably in a thead element
    <tbody>
        @Html.EditorFor(m => m.LeaveDetailsList)
    </tbody>
</table>

и, наконец, в контроллере

public ActionResult Edit(LeaveBalanceViewModel model)
{
    // iterate over model.LeaveDetailsList and save the items
}
64
задан 7 revs, 6 users 67% 15 September 2014 в 16:51
поделиться

14 ответов

Вы можете представить свой лабиринт как дерево.

     A
    / \
   /   \
  B     C
 / \   / \
D   E F   G
   / \     \
  H   I     J
 / \
L   M
   / \
  **  O

(which could possibly represent)

        START
        +   +---+---+
        | A   C   G |
    +---+   +   +   +
    | D   B | F | J |
+---+---+   +---+---+
| L   H   E   I |
+---+   +---+---+
    | M   O |
    +   +---+
    FINISH

(ignoring left-right ordering on the tree)

Где каждый узел является соединением путей. D, I, J, L и O - тупики, а ** - цель. Конечно, в вашем фактическом дереве каждый узел имеет возможность иметь до три детей.

Ваша цель теперь просто найти, какие узлы пересекаются, чтобы найти финиш , Любой алгоритм поиска дерева ol будет делать.

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

A B E H M **

Обратите внимание, что этот подход становится незначительно более сложным, когда у вас есть «петли» в вашем лабиринте (т. е. когда это возможно, без обратного слежения, вы снова вводите проход, который вы мы уже прошли).

Теперь давайте посмотрим на ваше первое решение, которое вы упомянули, применительно к этому дереву.

Ваше первое решение в основном - это Depth-First Поиск , что действительно не так уж плохо. На самом деле это довольно хороший рекурсивный поиск. В основном, в нем говорится: «Сначала используйте самый правый подход. Если ничего нет, отступите назад до первого места, вы можете пойти прямо или влево, а затем повторить.

Поиск по глубине будет искать выше дерево в этом порядке:

A B D (backtrack) E H L (backtrack) M ** (backtrack) O (backtrack thrice) I
(backtrack thrice) C F (backtrack) G J

Обратите внимание, что вы можете остановиться, как только найдете **.

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

Еще один способ поиска дерева - это .

Другой способ поиска дерева - это Breadth-First , который просматривает деревья по глубине. Он выполнил поиск по указанному выше дереву в следующем порядке:

A (next level) B C (next level) D E F G (next level)
H I J (next level) L M (next level) ** O

Обратите внимание, что из-за характера лабиринта ширина -начало имеет гораздо более высокое среднее количество узлов, которые он проверяет. Первый путь легко реализуется с помощью очереди путей для поиска, и каждая итерация, выбирая путь из очереди, «использует ding it ", получив все пути, через которые он может перейти после одного шага, и поместив эти новые пути в конец очереди. Нет никаких явных команд «следующего уровня» для кода, и они были там, чтобы помочь понять.

На самом деле существует целый расширенный список способов поиска дерева . Я просто упомянул два простых, самых простых способа.

Если ваш лабиринт очень, очень длинный и глубокий, имеет петли и сумасшествия, и это сложно, я предлагаю A * , который является стандартным алгоритмом поиска пути, который сочетает в себе поиск по методу «Ширина-Первый» с эвристикой ... вроде как «интеллектуальный поиск по ширине».

Он в основном работает следующим образом:

  1. Поместите один путь в очередь (путь, по которому вы проходите только один шаг прямо в лабиринт). Путь имеет «вес», задаваемый его текущей длиной + его прямолинейным расстоянием от конца (который можно вычислить математически)
  2. Поставить путь с наименьшим весом из очереди.
  3. «Взорвать» путь на каждый путь, который может быть после одного шага. (т. е. если ваш путь находится справа слева влево, то ваши разнесенные пути - это R L L R R и R L L R L, не считая незаконных, которые проходят через стены).
  4. Если у одного из этих путей есть цель, то Victory! В противном случае:
  5. Рассчитайте весы взорванных путей и поместите все их обратно в очередь (не включая исходный путь).
  6. Сортировка очереди по весу, самая низкая первая. Затем повторите шаг № 2

И это A *, который я представляю специально выделенным, потому что это более или менее стандартный алгоритм поиска путей для всех приложений для поиска путей , в том числе перемещение от одного края карты к другому, избегая внедорожных дорожек или гор и т. д. Это работает так хорошо, потому что использует кратчайшее расстояние эвристического расстояния , что дает ему «интеллект». A * настолько универсален, потому что, учитывая любую проблему, если у вас есть минимально возможная эвристика расстояния (наша простая - прямая линия), вы можете применить ее.

НО, но это имеет большое значение для обратите внимание, что A * - , а не ваш единственный вариант.

Фактически, в категория википедии алгоритмов обхода дерева перечислены только 97! (лучшее будет по-прежнему находиться на этой странице , связанное ранее)

Извините за длину = P (я имею тенденцию блуждать)

149
ответ дан Justin L. 28 August 2018 в 20:06
поделиться

Просто идея. Почему бы не бросить туда некоторых ботов в стиле monte carlo. Назовем первое поколение ботов gen0. Мы сохраняем ботов от gen0, у которых есть некоторые непрерывные дороги таким образом: от начала до некоторой точки или от некоторой точки до конца

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

Итак, для genn мы пытаемся соединиться с формой ботов gen0, gen1 , ..., genn-1.

Конечно, поколение длится всего лишь конечное количество времени.

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

некоторые хорошие сайты для идей: http://citeseerx.ist.psu.edu/ http: // arxiv.org/

2
ответ дан 19021programmer 28 August 2018 в 20:06
поделиться

Интересный подход, по крайней мере, мне показалось интересным, - использовать клеточные автоматы. Короче говоря, «космическая» ячейка, окруженная 3-дюймовыми «ячейками», превращается в «стенную» ячейку. В конце остаются только оставшиеся ячейки, оставшиеся на пути к выходу.

Если вы посмотрите на дерево, которое Джастин положил в свой ответ, вы увидите, что листовые узлы имеют 3 стены. Обрезайте дерево до тех пор, пока у вас не будет пути.

11
ответ дан Andre Artus 28 August 2018 в 20:06
поделиться

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

предположим, что у вас есть следующие свойства ...

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

, тогда вы можете спроектировать AI который ...

  • рисует карту - каждый раз, когда получает новую информацию о лабиринте.
  • вычисляет минимальную известную длину пути между всеми ненаблюдаемыми позициями (и сама и пункт назначения).
  • может устанавливать приоритеты ненаблюдаемых позиций для проверки на основе окружающих структур. (если невозможно достичь цели оттуда ...)
  • может устанавливать приоритеты ненаблюдаемых позиций для проверки на основе направления и расстояния до места назначения.
  • может определять приоритеты ненаблюдаемых позиций для проверки основанный на опыте сбора информации. (как далеко он может видеть в среднем и как далеко он должен ходить?)
  • может определить приоритеты ненаблюдаемых позиций, чтобы найти возможные ярлыки. (опыт: много ли циклов?)
1
ответ дан comonad 28 August 2018 в 20:06
поделиться

Не специально для вашего случая, но я столкнулся с несколькими вопросами программирования, где я нашел алгоритм Ли весьма удобным для быстрого кода. Он не самый эффективный для всех случаев, но легко вывернуться. Вот one Я взломал для конкурса.

0
ответ дан Jubin Chheda 28 August 2018 в 20:06
поделиться

У меня была аналогичная проблема в одном из моих университетских Comp. Sci. курсы. Решение, которое мы придумали, состояло в том, чтобы следовать за левой стенкой (правая стенка будет работать так же хорошо). Вот какой-то псевдокод

While Not At End
    If Square To Left is open,
        Rotate Left
        Go Forward
    Else
        Rotate Right
    End If
Wend

Это в основном это. Сложная часть отслеживает, в каком направлении ваша сторона, и выяснить, какая позиция сетки находится слева от вас в зависимости от этого направления. Это сработало для любого тестового примера, с которым я столкнулся. Довольно интересно, что решение «Профессора» было чем-то вроде:

While Not At End
    If Can Go North
        Go North
    ElseIf Can Go East
        Go East
    ElseIf Can Go South
        Go South
    ElseIf Can Go West 
        Go West
    EndIf
Wend

. Это будет хорошо работать для большинства простых лабиринтов, но не работает в лабиринте, который выглядит следующим образом:

SXXXXXXXXXXXXX
   X         X
   X         X
   X         X
 XXX         X
 X X         X
 X XXXXXXXXXXX     XXXE
 X                 X
 XXXXXXXXXXXXXXXXXXX

Когда S и E являются началом и концом.

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

1
ответ дан Kibbee 28 August 2018 в 20:06
поделиться

Как насчет построения графика из вашей Матрицы и использования первого поиска Breadth, первого поиска или алгоритма Дейкстры?

4
ответ дан Kungi 28 August 2018 в 20:06
поделиться

Это один из моих любимых алгоритмов когда-либо ....

1) Move forward
2) Are you at a wall?
2a) If yes, turn left
3) Are you at the finish?
3a) If no, go to 1
3b) If yes, solved
4
ответ дан Nate Noonen 28 August 2018 в 20:06
поделиться

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

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

1
ответ дан Norman Ramsey 28 August 2018 в 20:06
поделиться

Этот алгоритм azkaban также может помочь вам, http://journals.analysisofalgorithms.com/2011/08/efficient-maze-solving-approach-with.html

0
ответ дан raghavankl 28 August 2018 в 20:06
поделиться

Тот же ответ, что и все вопросы о переполнении стека;)

Используйте vi!

http://www.texteditors.org/cgi-bin/wiki. pl? Vi-Maze

Поистине увлекательно видеть, как текстовый редактор решает ascii-лабиринт, я уверен, что у парней emacs есть эквивалент ..

0
ответ дан schemathings 28 August 2018 в 20:06
поделиться

Лучшим способом решения лабиринта является использование алгоритма подключения, такого как union-find, который является квазилинейным алгоритмом времени, предполагающим сжатие пути.

Union-Find - это структура данных, которая говорит вам, что транзисторно соединены два элемента в наборе.

Чтобы использовать структуру данных поиска соединения для решения лабиринта, сначала данные о соседних связях используются для построения структуры данных объединения. Тогда нахождение объединения сжимается. Чтобы определить, разрешен ли лабиринт, сравниваются входные и выходные значения. Если они имеют одинаковое значение, то они связаны и лабиринт разрешима. Наконец, чтобы найти решение, вы начинаете с входа и исследуете корень, связанный с каждым из его соседей. Как только вы обнаружите ранее невидимого соседа с тем же корнем, что и текущая ячейка, вы заходите в эту ячейку и повторяете процесс.

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

0
ответ дан Tyler Durden 28 August 2018 в 20:06
поделиться

Это очень простое представление для моделирования лабиринта в C ++:)

#ifndef vAlgorithms_Interview_graph_maze_better_h
#define vAlgorithms_Interview_graph_maze_better_h

static const int kMaxRows = 100;
static const int kMaxColumns = 100;

class MazeSolver
    {
private:
    char m_matrix[kMaxRows][kMaxColumns]; //matrix representation of graph
    int rows, cols; //actual rows and columns

    bool m_exit_found;
    int m_exit_row, m_exit_col;
    int m_entrance_row, m_entrance_col;

    struct square //abstraction for data stored in every verex
        {
        pair<int, int> m_coord; //x and y co-ordinates of the matrix
        square* m_parent; //to trace the path backwards

        square() : m_parent(0) {}
        };

    queue<square*> Q;

public:
    MazeSolver(const char* filename)
        : m_exit_found(false)
        , m_exit_row(0)
        , m_exit_col(0)
        , m_entrance_row(0)
        , m_entrance_col(0)
        {
        ifstream file;
        file.open(filename);

        if(!file)
            {
            cout << "could not open the file" << endl << flush;
            // in real world, put this in second phase constructor
            }
        init_matrix(file);
        }
    ~MazeSolver()
        {
        }
    void solve_maze()
        {
        //we will basically use BFS: keep pushing squares on q, visit all 4 neighbors and see
        //which way can we proceed depending on obstacle(wall)

        square* s = new square();
        s->m_coord = make_pair(m_entrance_row, m_entrance_col);

        Q.push(s);

        while(!m_exit_found && !Q.empty())
            {
            s = Q.front();
            Q.pop();

            int x = s->m_coord.first;
            int y = s->m_coord.second;
            //check if this square is an exit cell
            if(x == m_exit_row && y == m_exit_col)
                {
                m_matrix[x][y] = '>'; // end of the path
                m_exit_found = true;
                //todo: try breaking? no= queue wont empty
                }
            else
                {
                //try walking all 4 neighbors and select best path
                //NOTE: Since we check all 4 neighbors simultaneously,
                //      the path will be the shortest path
                walk_path(x-1, y, s);
                walk_path(x+1, y, s);
                walk_path(x, y-1, s);
                walk_path(x, y+1, s);
                }
            } /* end while */

        clear_maze(); //unset all previously marked visited shit

        //put the traversed path in maze for printing
        while(s->m_parent)
            {
            m_matrix[s->m_coord.first][s->m_coord.second] = '-';
            s = s->m_parent;
            } /* end while */
        }

    void print()
        {
        for(int i=0; i<rows; i++)
            {
            for(int j=0; j<cols; j++)
                cout << m_matrix[i][j];
            cout << endl << flush;
            }
        }

private:
    void init_matrix(ifstream& file)
        {
        //read the contents line-wise
        string line;
        int row=0;
        while(!file.eof())
            {
            std::getline(file, line);
            for(int i=0; i<line.size(); i++)
                {
                m_matrix[row][i] = line[i];
                }
            row++;
            if(line.size() > 0)
                {
                cols = line.size();
                }
            } /* end while */
        rows = row - 1;

        find_exit_and_entry();
        m_exit_found = false;
        }

    //find and mark ramp and exit points
    void find_exit_and_entry()
        {
        for(int i=0; i<rows; i++)
            {
            if(m_matrix[i][cols-1] == ' ')
                {
                m_exit_row = i;
                m_exit_col = cols - 1;
                }
            if(m_matrix[i][0] == ' ')
                {
                m_entrance_row = i;
                m_entrance_col = 0;
                }
            } /* end for */
        //mark entry and exit for testing
        m_matrix[m_entrance_row][m_entrance_col] = 's';
        m_matrix[m_exit_row][m_exit_col] = 'e';
        }

    void clear_maze()
        {
        for(int x=0; x<rows; x++)
            for(int y=0; y<cols; y++)
                if(m_matrix[x][y] == '-')
                    m_matrix[x][y] = ' ';
        }
        // Take a square, see if it's the exit. If not, 
        // push it onto the queue so its (possible) pathways
        // are checked.
    void walk_path(int x, int y, square* parent)
        {
        if(m_exit_found) return;
        if(x==m_exit_row && y==m_exit_col)
            {
            m_matrix[x][y] = '>';
            m_exit_found = true;
            }
        else
            {
            if(can_walk_at(x, y))
                {
                //tag this cell as visited
                m_matrix[x][y] = '-';

                cout << "can walk = " << x << ", " << y << endl << flush;

                //add to queue
                square* s = new square();
                s->m_parent = parent;
                s->m_coord = make_pair(x, y);
                Q.push(s);
                }
            }
        }

    bool can_walk_at(int x, int y)
        {
        bool oob = is_out_of_bounds(x, y);
        bool visited = m_matrix[x][y] == '-';
        bool walled = m_matrix[x][y] == '#';

        return ( !oob && !visited && !walled);
        }
    bool is_out_of_bounds(int x, int y)
        {
        if(x<0 || x > rows || y<0 || y>cols)
            return true;
        return false;
        }
    };


void run_test_graph_maze_better()
        {
        MazeSolver m("/Users/vshakya/Dropbox/private/graph/maze.txt");
        m.print();
        m.solve_maze();
        m.print();
        }


#endif
3
ответ дан Viren 28 August 2018 в 20:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: