【问题标题】:Recursive Backtracking Does Not Back Track递归回溯不回溯
【发布时间】:2021-12-28 17:15:00
【问题描述】:

我一直在努力使用 C++ 中的隐性回溯解决以下问题。问题是它不会回溯。我在纸上手动跟踪了我的算法,它在纸上有效。所以问题是我不知道如何在 C++ 中实现它。任何帮助将不胜感激。

问题:

给定一个表示地图高程的二维网格,确定最低点和最高点,以及它们之间是否存在永不下降的路径。

输入

您的程序将收到以下命令行参数:

<fname> File name for the 2-dimensional map
<M>     Number of rows
<N>     Number of columns

输出

您的程序应该将 5 个值写入标准输出: Lr Lc Hr Hc YESNO 其中 Lr Lc 是网格中最低点的行和列,Hr Hc 是网格中最高点的行和列, YESNO 是这个词:如果从最低点到最高点的路径永不下降,则为是;如果没有这样的路径,则为否。具体来说,路径从最低点开始,并且只能从一个点到其 4 个邻居(左、右、上或下)中的一个,该点的海拔不低于该点。输入将有一个唯一的解决方案。

问题出在“路径”功能上。

#include <iostream>
#include <fstream>
#include<string>
#include <vector>
#include <algorithm>
#include <iostream>
#include<sstream>
// using namespace std;

void ReadFile(std::string fname, std::vector<std::vector<int>> *const vec_2d);

// What about min? row and col are initially the min, but then get updated
void min_max(std::vector<std::vector<int>> *const vec_2d,
             std::vector<int> &vec_1d,
             int num_rows,
             int num_cols,
             int &row,
             int &col,
             int &idx_i_max,
             int &idx_j_max,
             int &cur_val); //grid is vec_2d??????
             
int path(std::vector<int> vec_1d,
         int row,
         int col,
         int num_rows,
         int num_cols,
         int idx_i_max,
         int idx_j_max,
         int &cur_val); // bool *visited is a pointer type bool which could be a 2-d array??
         
int main(int argc, char *argv[])
{
    
    std::vector<std::vector<int>> vec_2d;
    
    std::vector<int> vec_1d;
    // declare variables
    int num_rows, num_cols, row, col, idx_i_max, idx_j_max, cur_val;
    
    std::string fname;
    
    // get .txt file containing the grid
    fname = argv[1]; //string of file name
            
    num_rows = atoi(argv[2]); // convert argument strings to integers
    num_cols = atoi(argv[3]);
    
    // bool visited[100][100];
    //2D vector initialized with user defined size
    // std::vector<std::vector<int>> visited(num_rows, std::vector<int>(num_cols));
    
    ReadFile(fname, &vec_2d); //reading the .txt file and assigning to vec_2d
             
    min_max(&vec_2d,
            vec_1d,
            num_rows,
            num_cols,
            row,
            col,
            idx_i_max,
            idx_j_max,
            cur_val);
    
    path(vec_1d, row, col, num_rows, num_cols, idx_i_max, idx_j_max, cur_val);
}

void ReadFile(std::string fname, std::vector<std::vector<int>> *const vec_2d)
{ //it is a pointer to a vector,therefore, after end of func, it will still exist // Create the input filestream - opens the file & prepares it for reading

    std::ifstream file(fname);
    
    std::string str; // Temporary string to hold a single line of the file
    
    while (std::getline(file, str))
    { // Reads all lines in the file, 1 at at time
    
        std::vector<int> new_row; // Creates a temporary vector to represent one row
        
        std::istringstream ss(str); // Converts our string into a stringstream
        
        int token; // Temp int to store a converted value from a line
        
        while (ss >> token)
        { // Reads all values from the stringstream (current row), converts to int
        
            new_row.push_back(token); // Adds the converted value to the row
        }
        
        vec_2d->push_back(new_row); // Pushes our constructed vector of ints to the 2D vector
    }
}

void min_max(std::vector<std::vector<int>> *const vec_2d,
             std::vector<int> &vec_1d,
             int num_rows,
             int num_cols,
             int &row,
             int &col,
             int &idx_i_max,
             int &idx_j_max,
             int &cur_val)
{ //I dont need any argument for this func

    //Converting 2-d vec to 1-d to find loc of min and max
    
    for (int i = 0; i < (*vec_2d).size(); i++)
    {
        
        for (int j = 0; j < (*vec_2d)[i].size(); j++)
        {
            
            vec_1d.push_back((*vec_2d)[i][j]);
        }
    }
    // finding the max and min values in the grid vector and save thier index (max_idx and min_idx)
    int max_idx, min_idx; // Initialize two int for index of max and min values
            
    // 
    int maxElementIndex = std::max_element(vec_1d.begin(), vec_1d.end())
            - vec_1d.begin(); //max elem index //I need to convert 2d to 1d vector to use this func
            
    int minElementIndex = std::min_element(vec_1d.begin(), vec_1d.end())
            - vec_1d.begin(); //min elem index
            
            //convert 1-d  vec idx to 2-d vec idx
    idx_i_max = (maxElementIndex / num_cols) + 1; //actual idx + 1
            
    idx_j_max = (maxElementIndex % num_cols) + 1; //actual idx + 1
            
    int idx_i_min = (minElementIndex / num_cols) + 1; //actual idx + 1
            
    int idx_j_min = (minElementIndex % num_cols) + 1; //actual idx + 1
            
    //      The initial current value is the minimum
    cur_val = *std::min_element(vec_1d.begin(), vec_1d.end());
    
    //loc of min will be our start point as below
    row = idx_i_min; //actual idx + 1
            
    col = idx_j_min; //actual idx + 1
            
    // print i and j idx of min and max respectively (with a space after each)
    
    std::cout << idx_i_min << " ";
    
    std::cout << idx_j_min << " ";
    
    std::cout << idx_i_max << " ";
    
    std::cout << idx_j_max << " "; //This prints are working fine
            
    // A recursive backtracking function to go over all cells. base case is when all directions are impossible, then retuen 0
}
//row and col will be changed in every recursion. should they be const???
int path(std::vector<int> vec_1d,
         int row,
         int col,
         int num_rows,
         int num_cols,
         int idx_i_max,
         int idx_j_max,
         int &cur_val)
{
    
    //  std::cout<<"test"<<std::endl;
    
    std::cout << std::endl << row << " " << col << std::endl; // it atops at the second cell
            
    // std::cout<<cur_val<<std::endl;//it prints the start point twice
    
    // if the evaluating neighbor cell is equal to max value
    if (row == idx_i_max && col == idx_j_max)
    { //base case
    
        std::cout << "yes";
        
        return 1;
    }
    
    else
    {
        
        cur_val = vec_1d[((row - 1) * num_cols) + (col - 1)]; //updating the current value  
                
        //Checking the north neighbor (COND1)
        if (row - 1 > 0
                && vec_1d[((row - 1 - 1) * num_cols) + (col - 1)] >= cur_val)
        { //if the north cell is -1
        
            vec_1d[((row - 1) * num_cols) + (col - 1)] = -1; // making the current cell as visited
                    
            path(vec_1d,
                 row - 1,
                 col,
                 num_rows,
                 num_cols,
                 idx_i_max,
                 idx_j_max,
                 cur_val);
            
            return 1;
        }
        
        //Checking the south neighbor(COND2)
        if (row + 1 <= num_rows
                && vec_1d[((row + 1 - 1) * num_cols) + (col - 1)] >= cur_val)
        {
            
            vec_1d[((row - 1) * num_cols) + (col - 1)] = -1;
            
            path(vec_1d,
                 row + 1,
                 col,
                 num_rows,
                 num_cols,
                 idx_i_max,
                 idx_j_max,
                 cur_val);
            return 1;
        }
        
        //Checking the west neighbor(COND3)
        if (col - 1 > 0
                && vec_1d[((row - 1) * num_cols) + (col - 1 - 1)] >= cur_val)
        {
            
            vec_1d[((row - 1) * num_cols) + (col - 1)] = -1;
            
            path(vec_1d,
                 row,
                 col - 1,
                 num_rows,
                 num_cols,
                 idx_i_max,
                 idx_j_max,
                 cur_val);
            
            return 1;
        }
        
        //Checking the east neighbor(COND4)
        if (col + 1 <= num_cols
                && vec_1d[((row - 1) * num_cols) + (col + 1 - 1)] >= cur_val)
        {
            
            vec_1d[((row - 1) * num_cols) + (col - 1)] = -1;
            
            path(vec_1d,
                 row,
                 col + 1,
                 num_rows,
                 num_cols,
                 idx_i_max,
                 idx_j_max,
                 cur_val);
            
            return 1;
        }
        
        // return 0;
        
    }
    // FORGET ABOUT PRINTING YES/NO. FOCUS ON THE PRINT OF CURRENT CELL
    // if(path){
    
    //         std::cout<<"yes";
    // }
    // else{
    
    //         std::cout<<"no";
    // }
}

【问题讨论】:

  • 我从这段代码中得到a bunch of compiler warnings。您应该在开始调试之前解决它们。编译器可能会告诉你出了什么问题。
  • @user4581301奇怪的是我没有任何编译错误!
  • 没有错误。一个重要的警告是path 可以在不返回值的情况下退出,这不被视为硬错误,因为可以编写永远不会返回的函数,除非在返回所涵盖的特定情况下。此警告可能是编译器出错,但您需要确认在函数末尾注释掉 return 0; 不是错误或导致错误。
  • 您可以通过在path 函数中的最后一个} 之前放置一个std::cout &lt;&lt; "I'm in trouble" &lt;&lt; std::endl; 来验证您是否正在调用未定义的行为。如果你看到那个输出,你就知道你遇到了麻烦。该输出意味着您正在从一个要求您返回 int 的函数返回,但您没有这样做。

标签: c++ recursion backtracking recursive-backtracking


【解决方案1】:

这里有一个提示:

^ g++ Foo.cpp -Wall --std=c++17 -o Foo
Foo.cpp: In function ‘void min_max(std::vector<std::vector<int> >*, std::vector<int>&, int, int, int&, int&, int&, int&, int&)’:
Foo.cpp:107:23: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     for (int i = 0; i < (*vec_2d).size(); i++)
                     ~~^~~~~~~~~~~~~~~~~~
Foo.cpp:110:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
         for (int j = 0; j < (*vec_2d)[i].size(); j++)
                         ~~^~~~~~~~~~~~~~~~~~~~~
Foo.cpp:117:9: warning: unused variable ‘max_idx’ [-Wunused-variable]
     int max_idx, min_idx; // Initialize two int for index of max and min values
         ^~~~~~~
Foo.cpp:117:18: warning: unused variable ‘min_idx’ [-Wunused-variable]
     int max_idx, min_idx; // Initialize two int for index of max and min values
                  ^~~~~~~
Foo.cpp: In function ‘int path(std::vector<int>, int, int, int, int, int, int, int&)’:
Foo.cpp:273:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

在您的编译中添加-Wall 标志将告诉编译器帮助您发现愚蠢的错误。我会修复这些警告,看看您的问题是否会消失。

【讨论】:

  • 感谢您的提示,但不幸的是,它确实有助于了解我如何更正代码以修复回溯@Joseph Larson
  • 您是否尝试修复警告?最后一个可能很重要。