Кратчайший путь через несколько точек [C++]

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

X: "стена"

H: "контрольная точка" (не более 5)

G: начальная позиция (ровно одна)

Мне нужно найти минимальное количество ходов, необходимое для прохождения всех контрольных точек (H), начиная с Г. Отдельные движения могут быть горизонтальными или вертикальными, хотя диагональное движение может быть достигнуто путем объединения горизонтальных и вертикальных движений. Переход за пределы сетки или к стенам (X) невозможен.

Для сетки

    ..H..
    ..X.H
    G...X

ожидаемый ответ: 7.

Количество строк и столбцов в сетке может быть не более 20.

Я попытался написать код bfs для решения проблемы, но при тестировании с сеткой выше он выдал 6, что неверно.

Я не знаю, что я делаю неправильно. Может ли кто-нибудь помочь?

#include <iostream>
#include &lt;bits/stdc++.h>
#include &lt;algorithm>
#include &lt;cstdio>
#include &lt;stdlib.h>
#include &lt;cmath>
#include &lt;cstring>
#include &lt;math.h>
#include &lt;string>
#include &lt;sstream>
#include &lt;vector>
#include &lt;iomanip>
#include &lt;deque>
#include &lt;queue>

#define loop(i, n) for(int i = 0; i < n; i++)  
#define scan(x) do{while((x=getchar())<'0'); for(x-='0'; '0' < (_=getchar());x=(x<<3)+(x<<1)+_-'0');}while(0)  
#define ull unsigned long long  

char _;

using namespace std;
typedef pair <int, int> ipair;

int rows, columns, startx, starty, hiders;

char grid[20][20];
char buffer[255];

bool valid(int x, int y){  
    if(x >= 0 && x < rows && y >= 0 && y < columns && grid[x][y] != 'X')  
        return true;  
    return false;  
}  

int main(){  
    scanf("%i%i%i", &rows, &columns, &hiders);  

    //this is where I set up the grid, at put it in the grid array.  

    for(int i = 0; i < rows; i++){  
        scanf("%s", &buffer);  
        for(int j = 0; j < columns; j++){  
            if(buffer[j] == 'G'){  
                startx = i;  
                starty = j;  
            }  
            grid[i][j] = buffer[j];  
        }  
    }  

    queue<ipair> Q; //keeps track of positions  
    queue<int> DQ; //keeps track of distance  
    int found = 0; //how many checkpoints are found  

    Q.push(make_pair(startx, starty)); //push start pos  
    DQ.push(0);  

    while(!Q.empty()){  
        int x = Q.front().first; //check x  
        int y = Q.front().second; //check y  

        if(found == hiders){ //if we found the amount needed  
            printf("%i", DQ.front()); // print current distance  
            return 0;  
        }  

        if(grid[x][y] == 'H'){ //found checkpoint  
            found++; //found a hider  
        }  
        //if it's possible to move right  
        if(valid(x + 1, y)){  
            Q.push(make_pair(x+1, y));  
            DQ.push(DQ.front() + 1);  
        }  
        //if it's possible to move left  
        if(valid(x - 1, y)){  
            Q.push(make_pair(x-1, y));  
            DQ.push(DQ.front() + 1);  
        }  
        //if it's possible to move up  
        if(valid(x, y + 1)){  
            Q.push(make_pair(x, y + 1));  
            DQ.push(DQ.front() + 1);  
        }  
        //if it's possible to move down  
        if(valid(x, y - 1)){  
            Q.push(make_pair(x, y - 1));  
            DQ.push(DQ.front() + 1);  
        }  

        Q.pop();  
        DQ.pop();  
        grid[x][y] = 'X'; //set the current coordinates as visited/walls  
    }  
}  

person Boris    schedule 27.01.2015    source источник
comment
Я думаю, вам будет лучше задать этот вопрос на веб-сайте QA для интервью/соревнований по программированию. Но для того, чтобы максимизировать ваши шансы на получение ответа, пожалуйста, хотя бы приведите пример ввода и его ожидаемого правильного вывода.   -  person JohnTortugo    schedule 27.01.2015
comment
Мы также не можем легко сказать, что происходит не так, поэтому не могли бы вы рассказать нам? У вас есть проблемы со сборкой? Сбои во время выполнения? Неверный или неожиданный вывод? Пожалуйста, предоставьте нам более подробную информацию и, если возможно, попытайтесь сузить круг самостоятельно, запустив отладчик и пройдя код построчно, если это необходимо.   -  person Some programmer dude    schedule 27.01.2015
comment
обновил код и добавил комментарии. Моя проблема в том, что я получаю неправильные цифры.   -  person Boris    schedule 27.01.2015
comment
вам нужен кратчайший путь, чтобы все контрольные точки были покрыты?   -  person sashas    schedule 27.01.2015
comment
Мне все еще неясна постановка задачи, можете ли вы уточнить?   -  person sashas    schedule 27.01.2015
comment
@sasha Нам дана сетка, мы должны пересечь ее и найти кратчайшее расстояние, чтобы каждая контрольная точка (обозначенная буквой «H») была посещена.   -  person Boris    schedule 27.01.2015
comment
@BorisMediaProds Но возможно, что все контрольные точки не могут быть достигнуты, в этом случае вам нужно покрыть максимальное количество контрольных точек, которые могут быть достигнуты по кратчайшему пути, если это так, я бы предложил соответствующим образом обновить ваше описание проблемы.   -  person sashas    schedule 27.01.2015
comment
@sasha Гарантируется, что существует правильный путь.   -  person Boris    schedule 27.01.2015
comment
да, извините за то, что подумал, что X были контрольными точками, последнее уточнение, каким может быть максимальный размер сетки, количество контрольных точек?   -  person sashas    schedule 27.01.2015
comment
Кстати, нельзя называть глобальную переменную _.   -  person HolyBlackCat    schedule 27.01.2015
comment
@sasha максимальный размер сетки 20х20, максимальное количество контрольных точек 5.   -  person Boris    schedule 27.01.2015
comment
@BorisMediaProds Конечно, вы не можете решить вопрос только с помощью bfs (требуется bfs + битовая маска), но почему ваш код дает 6, это другой вопрос.   -  person sashas    schedule 27.01.2015
comment
в постановке задачи сказано, что может потребоваться рекурсия. Но я не знаю, как реализовать рекурсию или битовую маску.   -  person Boris    schedule 27.01.2015
comment
основная ошибка в вашем подходе заключается в том, что когда вы нашли последнюю контрольную точку и все контрольные точки пройдены, нет необходимости, чтобы все эти контрольные точки были пройдены на пути от G до последней пройденной контрольной точки. И мне очень жаль, но вам придется изучить рекурсию/битовую маску самостоятельно, и если вы сомневаетесь в этом, вы можете опубликовать это как новый вопрос :)   -  person sashas    schedule 27.01.2015
comment
то, что я пытаюсь сделать, это. Когда контрольная точка найдена из G, запустите новую BFS из этой позиции в любую другую контрольную точку. У вас есть идея, как я могу реализовать это в своем решении?   -  person Boris    schedule 27.01.2015
comment
Давайте продолжим обсуждение в чате.   -  person sashas    schedule 27.01.2015


Ответы (1)


Это не проблема, решаемая BFS.

На первый взгляд, Branch and Bound или Dynamic — это то, что вам нужно.

B&B определенно доставит вас туда, но его сложно реализовать, и он медленнее, чем Dynamic.

Первая динамика, которая приходит на ум, потребует 5 сеток 20x20, но я не уверен в этом на 100% (это обратная связь с первого взгляда).

person MichaelCMS    schedule 28.01.2015