Модераторы: Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [C&C++] Виртуальный робот в лабиринте, Поиск решения лабиринта 
V
    Опции темы
student117
Дата 17.8.2011, 01:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 17.8.2011

Репутация: нет
Всего: нет



Робот идёт по лабиринту размером X на Y.
Начинает всегда в координате (1,0) (т.е. (1,0) всегда коридор).
labirint[x][y] == 0 - стена
labirint[x][y] == 1 - коридор
Выход - 1 на краю лабиринта.
Программа должна выводить координаты маршрута в виду (x1,y1)(x2,y2)...(xN,yN)

Пример:
0,1,0,0,0,0,
0,1,1,1,0,0,
0,0,0,1,1,0,
0,1,1,1,0,0,
0,1,0,1,1,0,
0,1,0,0,0,0,
Решение: (1,0)(1,1)(2,1)(3,1)(3,2)(3,3)(2,3)(1,3)(1,4)(1,5)

Предпочтения:
Алгоритм должен быть как можно проще.
Читабельность важнее производительности.
Как можно меньше спецефичного С++ кода.

Я довел это до:
Код

unsigned short move_robot(short x, short y)
{ 
    // За пределами?
    if (x < 0 || x > MAX_X || y < 0 || y > MAX_Y)
    {
        return FALSE;
    }

    // Нашли выход и это не вход? 
    if (labirint[y][x] == 1 && (x != 1 && y != 0) && 
       (x == 0 || x == MAX_X-1 || y == 0 || y == MAX_Y-1))
    {
        labirint[y][x] = 4;
        return TRUE;
    }
 
    // Это не корридор?
    if (labirint[y][x] != 1)
    {
        return FALSE;
    }
 
    // Пометим как маршрут
    labirint[y][x] = 2;
 
    // Север
    if (move_robot(x, y-1) == TRUE)
    {
        return TRUE;
    }
 
    // Юг
    if (move_robot(x, y+1) == TRUE)
    {
        return TRUE;
    }

     // Запад
    if (move_robot(x-1, y) == TRUE)
    {
        return TRUE;
    }
 
    // Восток
    if (move_robot(x+1, y) == TRUE)
    {
        return TRUE;
    }
 
    // Пометим, что по этому маршруту ходить больше не надо
    labirint[y][x] = 3;
 
    return FALSE;
}

void print_solution(void)
{
    unsigned short y;
    unsigned short x;
 
 
    for (y = 0; y < MAX_Y; y++)
    {
        for (x = 0; x < MAX_X; x++)
        {
            if (labirint[y][x] == 2)
            {
                printf("(%d,%d)", x, y);
            }
            else if (labirint[y][x] == 4)
            {
                printf("(%d,%d)\n", x, y);
                printf("Exit at (%d,%d)\n", x, y);
            }
        }
    }
}

Код находит нужное решение при вызове move_robot(1, 0).

Моя проблема в том, что print_solution() выводит:
(1,0)(1,1)(2,1)(3,1)(3,2)(1,3)(2,3)(3,3)(1,4)(1,5)
Т.е. координаты "перепутаны", когда робот идёт с Запада на Восток. Аналогично будет если маршрут на выход будет с Юга на Север.

Есть идеи?
Сортировка?
Или надо перерабатывать алгоритм?

Спасибо.

Это сообщение отредактировал(а) student117 - 17.8.2011, 01:46
PM MAIL   Вверх
t_gran
  Дата 17.8.2011, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 621
Регистрация: 13.11.2007
Где: г.Усть-Илимск

Репутация: 33
Всего: 37



student117, всё довольно просто. Сохраняйте пройденный путь в стеке. Стек можете сами реализовать, либо воспользоваться STL. Вот что у меня получилось исходя из вашего кода:
Код

#include <cstdio>
#include <stack>

#define MAX_X 6
#define MAX_Y 6

unsigned labirint[MAX_Y][MAX_X] = {{0,1,0,0,0,0},
                                   {0,1,1,1,0,0},
                                   {0,0,0,1,1,0},
                                   {0,1,1,1,0,0},
                                   {0,1,0,1,1,0},
                                   {0,1,0,0,0,0}};

struct TCoord
{
   short x, y;
};
                                   
std::stack<TCoord> stack;

//----------------------------------------------//
bool move_robot(short x, short y,
                short fx, short fy)
{
   if (x < 0 || x > MAX_X || y < 0 || y > MAX_Y)
   {
      return false;
   }

   // Это не корридор?
   if (labirint[y][x] != 1)
   {
      return false;
   }

   TCoord coord = {x, y};
   stack.push(coord);
   
   // Нашли выход и это не вход?
   if ((labirint[y][x] == 1) && (x == fx) && (y == fy))
   {
      labirint[y][x] = 4;
      return true;
   }

   // Пометим как маршрут
   labirint[y][x] = 2;
   
   // Север
   if (move_robot(x, y - 1, fx, fy) == true)
   {
      return true;
   }

   // Юг
   if (move_robot(x, y + 1, fx, fy) == true)
   {
      return true;
   }
   // Запад
   if (move_robot(x - 1, y, fx, fy) == true)
   {
      return true;
   }

   // Восток
   if (move_robot(x + 1, y, fx, fy) == true)
   {
      return true;
   }

   labirint[y][x] = 3;
   stack.pop();
   
   return false;
}
//----------------------------------------------//
void print_solution()
{
   while (stack.empty() == false)
   {
      printf("(%d,%d)", stack.top().x, stack.top().y);
      stack.pop();
   }
}
//----------------------------------------------//
int main()
{
   move_robot(1, 5, 1, 0);
   print_solution();

   return 0;
}

Правда путь выводится в обратном порядке, но для этого есть очередь. Ведь так?!  smile 

Результат выполнения


--------------------
Я знаю, что ничего не знаю© Сократ
user posted image
PM MAIL WWW   Вверх
student117
Дата 17.8.2011, 11:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 17.8.2011

Репутация: нет
Всего: нет



спасибо, t_gran
не успел пока разобраться/вникнуть, но первая реакция:
1. Stack на STL может быть посчитан за C++. Предпочтение отдаётся коду с наименьшим спецфичным С++ синтаксисом.
2. По всей видимости код использует координаты выхода. Условием задачи координаты вызода не даны.
PM MAIL   Вверх
student117
Дата 17.8.2011, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 17.8.2011

Репутация: нет
Всего: нет



да, стэк работает.
в исходном коде на 25ой строке простое
Код

solution[i].x = x;
solution[i].y = y;
i++;


и на 52ой
Код

i--;

делают то что нужно. smile

Разумеется по хорошему нужно делать StackPush(), StackPop(), IsStackFull(), IsStackEmpty() функционал.
Просто добавлять эти строки не безопасно.

t_gran, спасибо ещё раз за наводку.

Это сообщение отредактировал(а) student117 - 18.8.2011, 00:53
PM MAIL   Вверх
Silent
Дата 17.8.2011, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 252
Регистрация: 3.10.2006

Репутация: 6
Всего: 9



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

#include <stdio.h>

const int N = 10;
int dx[4] = {-1,0,1,0},
    dy[4] = {0,-1,0,1};

int labirint[N][N];
int qx[N*N], qy[N*N], pred[N*N];
int head = 0, tail = 0;
int n;

void init()
{
    scanf("%d",&n);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            scanf("%d",&labirint[i][j]);
}

void out(int x)
{
    if (pred[x] == -1) printf("(0,1) ");
    else
    {
        out(pred[x]);
        printf("(%d,%d) ",qy[x]-1,qx[x]-1);
    }
}

bool solve()
{
    qx[0] = 1;
    qy[0] = 2;
    pred[0] = -1;
    bool F = true;
    while ((head <= tail) && F)
    {
        labirint[qx[head]][qy[head]] = head+2;
        for (int i = 0; i < 4; i++)
        {
            int kx = qx[head] + dx[i],
                ky = qy[head] + dy[i];
            if (labirint[kx][ky] == 1)
            {
                if (kx == n) F = false;
                tail++;
                qx[tail] = kx;
                qy[tail] = ky;
                pred[tail] = head;
            }
        }
        head++;
    }
    return !F;
}

void main()
{
    freopen("in.txt", "rt", stdin);
    freopen("out.txt", "wt", stdout);
    init();
    if (solve()) out(tail);
}

легко переделывается в чистый С (мне так кажется, хотя ни разу его не знаю)
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Центр помощи"

ВНИМАНИЕ! Прежде чем создавать темы, или писать сообщения в данный раздел, ознакомьтесь, пожалуйста, с Правилами форума и конкретно этого раздела.
Несоблюдение правил может повлечь за собой самые строгие меры от закрытия/удаления темы до бана пользователя!


  • Название темы должно отражать её суть! (Не следует добавлять туда слова "помогите", "срочно" и т.п.)
  • При создании темы, первым делом в квадратных скобках укажите область, из которой исходит вопрос (язык, дисциплина, диплом). Пример: [C++].
  • В названии темы не нужно указывать происхождение задачи (например "школьная задача", "задача из учебника" и т.п.), не нужно указывать ее сложность ("простая задача", "легкий вопрос" и т.п.). Все это можно писать в тексте самой задачи.
  • Если Вы ошиблись при вводе названия темы, отправьте письмо любому из модераторов раздела (через личные сообщения или report).
  • Для подсветки кода пользуйтесь тегами [code][/code] (выделяйте код и нажимаете на кнопку "Код"). Не забывайте выбирать при этом соответствующий язык.
  • Помните: один топик - один вопрос!
  • В данном разделе запрещено поднимать темы, т.е. при отсутствии ответов на Ваш вопрос добавлять новые ответы к теме, тем самым поднимая тему на верх списка.
  • Если вы хотите, чтобы вашу проблему решили при помощи определенного алгоритма, то не забудьте описать его!
  • Если вопрос решён, то воспользуйтесь ссылкой "Пометить как решённый", которая находится под кнопками создания темы или специальным флажком при ответе.

Более подробно с правилами данного раздела Вы можете ознакомится в этой теме.

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Poseidon, Rodman

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Центр помощи | Следующая тема »


 




[ Время генерации скрипта: 0.0476 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.