在复杂的代码中,递归似乎不会停止
Recursion does not seem to stop in a complicated code
我编写了一个程序,在某些条件下生成所有可能的矩阵。
接受参数'r'和'n',其中'r'是矩阵中行或列的数目,'n'是每行或每列的和的最大数目
条件为:
- 每一行和每一列的所有条目按非升序排列
- 每一行和每一列的总和应小于或等于'n'
- 主对角线上的项按非升序排列(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;
}
首先,注意:您的代码有许多问题。建议你用一种容易让别人帮忙的方式来发布问题。您的代码没有按照发布的方式编译,并且需要使用第三方头文件。析构函数和构造函数都有错误。无论如何,对于r
和n
都等于1
的情况下的问题,下面一行是问题:
std::vector<int> gen_row(r-1, 0);
在函数genWat
内部调用。当r
等于1
时,您将尝试创建大小为0
的矢量。就其本身而言,这并不一定是个问题。但是随后调用isNonAscending
并尝试检查第0个索引——但是第0个索引不存在,因为向量的大小为0!
在尝试修复无限循环问题之前,我会专注于修复最简单的情况(r = 1
和n = 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
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 递归列出所有目录中的C++与Python与Ruby的性能
- 递归计数给定目录的文件和所有目录
- 关于记忆后这种递归关系的时间复杂度
- 以下递归代码的时间复杂度是多少?
- 递归回文问题的时间复杂度,C++
- 递归基转换时间复杂度分析
- 复杂的尾部递归情况
- 递归函数的时间复杂度计算
- 递归函数的最小空间复杂度是否为 O(N)
- O(n^m) 复杂度的递归算法
- 加泰罗尼亚数字,递归函数时间复杂度
- 递归函数的渐近时间复杂度
- 在复杂的代码中,递归似乎不会停止
- 下面使用Map和Vector实现递归级阶遍历的时间复杂度是多少
- 递归算法的复杂度
- 这个递归函数的时间复杂度是多少?
- 这个递归函数的时间复杂度是多少?