在复杂的代码中,递归似乎不会停止

Recursion does not seem to stop in a complicated code

本文关键字:递归 复杂 代码      更新时间:2023-10-16

我编写了一个程序,在某些条件下生成所有可能的矩阵。

接受参数'r'和'n',其中'r'是矩阵中行或列的数目,'n'是每行或每列的和的最大数目

条件为:

  1. 每一行和每一列的所有条目按非升序排列
  2. 每一行和每一列的总和应小于或等于'n'
  3. 主对角线上的项按非升序排列(m[i][i]>= m[j][j]对于所有i>j)

它还必须生成满足条件的所有可能性。

我的方法是先生成第0行和第0列,然后是第1行和第1列,以此类推,直到第r行和第r列。

我通过使用for循环迭代地设置左顶条目,并使用该左顶条目调用genWat函数来生成所有可能的行条目和列条目,使用Boost库与替换相结合(http://photon.poly.edu/~hbr/boost/combination.hpp)

然后检查条件,如果生成的条目符合条件(通过测试),则将它们存储在矩阵中(类Wat中的m),并且再次存储在下一行和列中(我称之为"target")。例如,如果它正在处理第二行和第二列,目标是2)迭代地设置左顶条目,并使用这些左顶条目递归地调用genWat函数。

直到生成第r行和第r列(target == r),如果第r行和第r列满足条件,则将该Wat存储到Wat的向量中。

这可能是我写过的最复杂的程序,很大程度上是因为它同时使用了递归和迭代,我发现这个问题真的很有趣,但我不能使它工作,不得不寻求帮助。

它可以编译,但是当我用一些小值r和n运行程序时,比如2和4,它会一直运行下去。对于r=1,抛出out_of_bounds异常。

我认为递归没有退出,因为递归的基本情况没有定义好,但我不知道为什么程序不工作。

代码确实很乱,很长,很复杂,但请帮我弄清楚如何解决这个问题。

谢谢。

    #include<iostream>
    #include<vector>
    #include<string>
    #include<stdlib.h>
    #include<algorithm>
    #include"combination.hpp"
    using namespace std;
    class Wat {
     public:
        int r, n;
        vector<vector<int> > m;
        vector<int> sumRow;
        vector<int> sumCol;
        Wat(const int r, const int n)
         : r(r), n(n)
           m(vector<vector<int> > (r, vector<int> (r, 0))),
           sumRow(vector<int> (r, 0)),
           sumCol(vector<int> (r, 0)) { }
        ~Wat() {
            //delete m;
            //delete sumRow;
            //delete sumCol;
        }
        Wat(const Wat& source) {
            r=source.r;
            n=source.n;
            m = source.m;
            sumRow = source.sumRow;
            sumCol = source.sumCol;
        }
        Wat operator=(const Wat& rhs) {
            Wat tmp(rhs);
            std::swap(r, tmp.r);
            std::swap(n, tmp.n);
            std::swap(m, tmp.m);
            std::swap(sumRow, tmp.sumRow);
            std::swap(sumCol, tmp.sumCol);
        }
        void index_assign(int row, int col, int item) {
            (m.at(row)).assign(col, item);
            sumRow[row] += item;
            sumCol[col] += item;
        }
        void row_assign(int row, int startColIdx, vector<int> items) {
            for(int i = 0; i < items.size(); ++i) {
                index_assign(row, startColIdx + i, items.at(i));
            }
        }
        void col_assign(int startRowIdx, int col, vector<int> items) {
            for(int i = 0; i < items.size(); ++i) {
                index_assign(startRowIdx + i, col, items.at(i));
            }
        }
        bool checkSumForRow(int target, const vector<int>& gen_row) const {
            bool ret = true;
            int testedSum = sumRow[target];
            for (int i=0; i<gen_row.size(); ++i) {
                if(sumCol[target+1+i] + gen_row[i] > n) {
                    ret = false;
                }
                testedSum += gen_row[i];
            }
            if (testedSum > n) {
                ret = false;
            }
            return ret;
        }
        bool checkSumForCol(int target, const vector<int>& gen_col) const {
            bool ret = true;
            int testedSum = sumCol[target];
            for (int i=0; i<gen_col.size(); ++i) {
                if(sumRow[target+1+i] + gen_col[i] > n) {
                    ret = false;
                }
                testedSum += gen_col[i];
            }
            if (testedSum > n) {
                ret = false;
            }
            return ret;
        }
    };
    bool isNonAscending (const vector<int>& v);
    void genWat(const Wat& w, int target, int r, int n, vector<Wat>& vw);
    int main(int argc, char** argv) {
        if(argc != 3) {
            cerr << "arguments: r and n" << endl;
            return 0;
        }
        else {
            vector<Wat> v;
            int r = atoi(argv[1]);
            int n = atoi(argv[2]);
            Wat waat(r, n); //starts from empty Wat, make a copy of previous Wat if needed, and add to v when complete
            for (int i = 0; i < n; ++i) {
                waat.index_assign(0, 0, i);
                genWat(waat, 0, r, n, v);
            }
            return 1;
        }
    }
    void genWat(const Wat& w, int target, int r, int n, vector<Wat>& vw) {
        if(target == r) {
            //compare the entries on each side beside diagonal first
            vw.push_back(w);
        }
        else if(target == r+1) {//might be the base case?? {
            return;
        }
        else {
            std::vector<int> gen_row(r-1, 0);
            do {
                if (isNonAscending(gen_row)) {
                    //need to define assignment operator, but actually to make it efficient, no need to make a copy here(just make a copy of sumRow and sumCol, and check the sum)
                    if (w.checkSumForRow(target, gen_row)) {
                        std::vector<int> gen_col(r-1, 0);
                        do {
                            if(isNonAscending(gen_col)) {
                                if(w.checkSumForCol(target, gen_col)) {
                                    Wat waaat = w;
                                    waaat.row_assign(target, target+1, gen_row);
                                    waaat.col_assign(target+1, target, gen_col);
                                    int leftTopBound = min((waaat.m)[target][target], waaat.n - max(waaat.sumRow[target+1], waaat.sumCol[target+1]));
                                    for (int i = 0; i < leftTopBound; ++i) {
                                        waaat.index_assign(target+1, target+1, i);
                                        genWat(waaat, target+1, r, n, vw);
                                    }
                                }
                            }
                        } while (boost::next_mapping(gen_col.begin(), gen_col.end(), 0, w.m[target][target]));
                    }
                }
            } while (boost::next_mapping(gen_row.begin(), gen_row.end(), 0, w.m[target][target]));
        }
    }
    bool isNonAscending (const vector<int>& v) {
        for(int i=0; i < v.size()-1; ++i) {
            if(v.at(i) < v.at(i+1)) {
                return false;
            }
        }
        return true;
    }

首先,注意:您的代码有许多问题。建议你用一种容易让别人帮忙的方式来发布问题。您的代码没有按照发布的方式编译,并且需要使用第三方头文件。析构函数和构造函数都有错误。无论如何,对于rn都等于1的情况下的问题,下面一行是问题:

std::vector<int> gen_row(r-1, 0);

在函数genWat内部调用。当r等于1时,您将尝试创建大小为0的矢量。就其本身而言,这并不一定是个问题。但是随后调用isNonAscending并尝试检查第0个索引——但是第0个索引不存在,因为向量的大小为0!

在尝试修复无限循环问题之前,我会专注于修复最简单的情况(r = 1n = 1)的崩溃。

EDIT:对于那些有兴趣看一看的人,下面的代码为我在VS2010上编译,我相信它遵循了原始代码的精神。显然,您还需要从问题中给出的链接下载combination.hpp

#include <iostream>
#include <vector>
#include <string>
#include <stdlib.h>
#include <algorithm>
#include "combination.hpp"
using namespace std;
class Wat {
public:
  int r, n;
  vector< vector<int> > m;
  vector<int> sumRow;
  vector<int> sumCol;
  Wat(const int r, const int n)
    : r(r), n(n), m(r), sumRow(r), sumCol(r) { }
  Wat(const Wat& source) {
    r=source.r;
    n=source.n;
    m = source.m;
    sumRow = source.sumRow;
    sumCol = source.sumCol;
  }
  Wat operator=(const Wat& rhs) {
    Wat tmp(rhs);
    std::swap(r, tmp.r);
    std::swap(n, tmp.n);
    std::swap(m, tmp.m);
    std::swap(sumRow, tmp.sumRow);
    std::swap(sumCol, tmp.sumCol);
  }
  void index_assign(int row, int col, int item) {
    (m.at(row)).assign(col, item);
    sumRow[row] += item;
    sumCol[col] += item;
  }
  void row_assign(int row, int startColIdx, vector<int> items) {
    for(int i = 0; i < items.size(); ++i) {
      index_assign(row, startColIdx + i, items.at(i));
    }
  }
  void col_assign(int startRowIdx, int col, vector<int> items) {
    for(int i = 0; i < items.size(); ++i) {
      index_assign(startRowIdx + i, col, items.at(i));
    }
  }
  bool checkSumForRow(int target, const vector<int>& gen_row) const {
    bool ret = true;
    int testedSum = sumRow[target];
    for (int i=0; i<gen_row.size(); ++i) {
      if(sumCol[target+1+i] + gen_row[i] > n) {
        ret = false;
      }
      testedSum += gen_row[i];
    }
    if (testedSum > n) {
      ret = false;
    }
    return ret;
  }
  bool checkSumForCol(int target, const vector<int>& gen_col) const {
    bool ret = true;
    int testedSum = sumCol[target];
    for (int i=0; i<gen_col.size(); ++i) {
      if(sumRow[target+1+i] + gen_col[i] > n) {
        ret = false;
      }
      testedSum += gen_col[i];
    }
    if (testedSum > n) {
      ret = false;
    }
    return ret;
  }
};
bool isNonAscending (const vector<int>& v);
void genWat(const Wat& w, int target, int r, int n, vector<Wat>& vw);
int main(int argc, char** argv) {
  if(argc != 3) {
    cerr << "arguments: r and n" << endl;
    return 0;
  }
  else {
    vector<Wat> v;
    int r = atoi(argv[1]);
    int n = atoi(argv[2]);
    Wat waat(r, n); //starts from empty Wat, make a copy of previous Wat if needed, and add to v when complete
    for (int i = 0; i < n; ++i) {
      waat.index_assign(0, 0, i);
      genWat(waat, 0, r, n, v);
    }
    return 1;
  }
}
void genWat(const Wat& w, int target, int r, int n, vector<Wat>& vw) {
  if(target == r) {
    //compare the entries on each side beside diagonal first
    vw.push_back(w);
  }
  else if(target == r+1) {//might be the base case?? {
    return;
  }
  else {
    std::vector<int> gen_row(r-1, 0);
    do {
      if (isNonAscending(gen_row)) {
        //need to define assignment operator, but actually to make it efficient, no need to make a copy here(just make a copy of sumRow and sumCol, and check the sum)
        if (w.checkSumForRow(target, gen_row)) {
          std::vector<int> gen_col(r-1, 0);
          do {
            if(isNonAscending(gen_col)) {
              if(w.checkSumForCol(target, gen_col)) {
                Wat waaat = w;
                waaat.row_assign(target, target+1, gen_row);
                waaat.col_assign(target+1, target, gen_col);
                int leftTopBound = min((waaat.m)[target][target], waaat.n - max(waaat.sumRow[target+1], waaat.sumCol[target+1]));
                for (int i = 0; i < leftTopBound; ++i) {
                  waaat.index_assign(target+1, target+1, i);
                  genWat(waaat, target+1, r, n, vw);
                }
              }
            }
          } while (boost::next_mapping(gen_col.begin(), gen_col.end(), 0, w.m[target][target]));
        }
      }
    } while (boost::next_mapping(gen_row.begin(), gen_row.end(), 0, w.m[target][target]));
  }
}
bool isNonAscending (const vector<int>& v) {
  for(int i=0; i < v.size()-1; ++i) {
    if(v.at(i) < v.at(i+1)) {
      return false;
    }
  }
  return true;
}

您提供的combination.hpp似乎不喜欢您的first_value和last_value相同。你让它生成从0到0的所有组合它永远不会停止。我把第269行改成了:

     if (++(*(--last)) != last_value)

     if (++(*(--last)) < last_value)

和代码不再无限长运行。

这不是一个正确的修复!我不知道next_mapping是否仍然正确地生成组合,并决定从这里留给你。

HTH