生成具有指定条目长度重复的有序选择
Posted
技术标签:
【中文标题】生成具有指定条目长度重复的有序选择【英文标题】:Generating an ordered selection with repetition of designated length of entry 【发布时间】:2013-07-05 17:34:06 【问题描述】:我正在编写一种模仿 unordered_tuple
的函数,来自 python 中的 sage combinatorial functions。
但不同的是,我使用的输入集始终是 [10, 9, 8, 7, 6],并且只有输入的数量不同(不大于 10)。
因此,entry = 3 和 entry = 4 的期望输出是,
unordered_tuples([10,9,8,7,6], 3)
[[6, 6, 6],
[6, 6, 7],
[6, 6, 8],
[6, 6, 9],
[6, 6, 10],
[6, 7, 7],
[6, 7, 8],
[6, 7, 9],
[6, 7, 10],
[6, 8, 8],
[6, 8, 9],
[6, 8, 10],
[6, 9, 9],
[6, 9, 10],
[6, 10, 10],
[7, 7, 7],
[7, 7, 8],
[7, 7, 9],
[7, 7, 10],
[7, 8, 8],
[7, 8, 9],
[7, 8, 10],
[7, 9, 9],
[7, 9, 10],
[7, 10, 10],
[8, 8, 8],
[8, 8, 9],
[8, 8, 10],
[8, 9, 9],
[8, 9, 10],
[8, 10, 10],
[9, 9, 9],
[9, 9, 10],
[9, 10, 10],
[10, 10, 10]]
unordered_tuples([10,9,8,7,6], 4)
[[6, 6, 6, 6],
[6, 6, 6, 7],
[6, 6, 6, 8],
[6, 6, 6, 9],
[6, 6, 6, 10],
[6, 6, 7, 7],
[6, 6, 7, 8],
[6, 6, 7, 9],
[6, 6, 7, 10],
[6, 6, 8, 8],
[6, 6, 8, 9],
[6, 6, 8, 10],
[6, 6, 9, 9],
[6, 6, 9, 10],
[6, 6, 10, 10],
[6, 7, 7, 7],
[6, 7, 7, 8],
[6, 7, 7, 9],
[6, 7, 7, 10],
[6, 7, 8, 8],
[6, 7, 8, 9],
[6, 7, 8, 10],
[6, 7, 9, 9],
[6, 7, 9, 10],
[6, 7, 10, 10],
[6, 8, 8, 8],
[6, 8, 8, 9],
[6, 8, 8, 10],
[6, 8, 9, 9],
[6, 8, 9, 10],
[6, 8, 10, 10],
[6, 9, 9, 9],
[6, 9, 9, 10],
[6, 9, 10, 10],
[6, 10, 10, 10],
[7, 7, 7, 7],
[7, 7, 7, 8],
[7, 7, 7, 9],
[7, 7, 7, 10],
[7, 7, 8, 8],
[7, 7, 8, 9],
[7, 7, 8, 10],
[7, 7, 9, 9],
[7, 7, 9, 10],
[7, 7, 10, 10],
[7, 8, 8, 8],
[7, 8, 8, 9],
[7, 8, 8, 10],
[7, 8, 9, 9],
[7, 8, 9, 10],
[7, 8, 10, 10],
[7, 9, 9, 9],
[7, 9, 9, 10],
[7, 9, 10, 10],
[7, 10, 10, 10],
[8, 8, 8, 8],
[8, 8, 8, 9],
[8, 8, 8, 10],
[8, 8, 9, 9],
[8, 8, 9, 10],
[8, 8, 10, 10],
[8, 9, 9, 9],
[8, 9, 9, 10],
[8, 9, 10, 10],
[8, 10, 10, 10],
[9, 9, 9, 9],
[9, 9, 9, 10],
[9, 9, 10, 10],
[9, 10, 10, 10],
[10, 10, 10, 10]]
我写的c++函数如下。
我其实不是一个经验丰富的程序员,我只是想提出正确的解决方案,但它工作正常,但它提供了很多重复的解决方案。
老实说,我写了函数,但我什至不知道我写了什么。
我可以使用set
,但是效率很低,我想知道这个问题的正确解决方案。
任何人都可以修复它以提供上面的输出吗?
#include<iostream>
#include<string>
#include<cstdlib>
#include<vector>
using namespace std;
vector<vector<int> > ut(int);
int main(int argc, char** argv)
int entry = atoi(argv[1]);
ut(entry);
return 1;
vector<vector<int> > ut(int entry)
vector<vector<int> > ret;
int upper = 10;
vector<int> v(entry, upper);
ret.push_back(v);
typedef vector<int>::iterator iter_t;
iter_t it = v.begin();
int count=0;
int c = 0;
while(v.back() != 6)
v = ret[count+c];
while(it != v.end())
--(*it);
++it;
ret.push_back(v);
++c;
it = v.begin();
c=0;
++count;
for(int i=0; i<ret.size(); ++i)
vector<int> tuple = ret[i];
for(int j=0; j<tuple.size(); ++j)
cout << tuple[j] << ' ';
cout<<endl;
cout << endl;
return ret;
【参考方案1】:
看这里:
vector<vector<int> > ret;
int upper = 10;
vector<int> v(entry, upper);
ret.push_back(v);
typedef vector<int>::iterator iter_t;
iter_t it = v.begin();
int count=0;
int c = 0;
while(v.back() != 6)
v = ret[count+c];
while(it != v.end())
--(*it);
++it;
ret.push_back(v);
++c;
it = v.begin();
c=0;
++count;
这只是可怕。 (我知道您是初学者;请理解我的批评旨在提供帮助。)如果不需要密集的复杂性并且可以作为错误的藏身之处,通常这种类型。请注意c
和it
设置在之前 循环和在循环的末尾,并且不再使用;我们可以将它们设置在循环的开头,代码会更短更清晰:
int count=0;
while(v.back() != 6)
iter_t it = v.begin();
int c = 0;
v = ret[count+c];
while(it != v.end())
--(*it);
++it;
ret.push_back(v);
++c;
++count;
现在我们可以看到c
除非它是零,否则它永远不会被使用。 (如果您不相信我,请查看原始代码。)但更糟糕的是it
指向v
,然后v
被分配了一个新值。所以it
可能指向死内存,取消引用它会导致未定义的行为。而且目前还不清楚这段代码是如何工作的。
试试这个:
vector<int> v(n,6);
vector<int>::iterator itr1;
do
ret.push_back(v);
itr1 = v.begin();
while(++(*itr1)>10)
if(++itr1==v.end())
break;
for(vector<int>::iterator itr2 = v.begin(); itr2!=itr1; ++itr2)
*itr2 = *itr1;
while(itr1!=v.end());
【讨论】:
【参考方案2】:递归是从排列问题开始的一个好地方。采用这种方法,要构建长度为 3 的所有输出,您从集合 [6, 7, 8, 9, 10]
中选择一个数字,然后将长度为 2 的所有输出附加到它上面,输入集合被限制为从所选数字开始。所以,如果,例如如果您选择了7
,则第一个递归调用的输入集将是[ 7, 8, 9, 10]
。即,在这种情况下,递归调用将附加到 [ 7 ]
所有长度为 2
的输出来自输入 [ 7, 8, 9, 10]
实现这个想法的程序如下。我很想看看是否有人能想出一个非递归的解决方案。
#include "stdafx.h"
#include <iostream>
#include <vector>
typedef std::vector<int> intvec;
typedef std::vector<intvec> intvecs;
void GenerateUnOrderedIntVecs(
const int* remainingInput, int remainingInputLen,
const intvec& outputSoFar, int remainingOutputLen,
intvecs& output)
if (remainingOutputLen == 0) // base case of recursion
output.push_back(outputSoFar);
return;
// For all digits in our input
for(int i=0; i<remainingInputLen; ++i)
// Add the ith digit to our output so far
intvec outputSoFar2(outputSoFar);
outputSoFar2.push_back(remainingInput[i]);
// The recursion
GenerateUnOrderedIntVecs(
remainingInput + i, // input set constrained to start from chosen digit
remainingInputLen - i, // input set is shorter
outputSoFar2, // one digit longer than the parameter outputSoFar
remainingOutputLen -1, // so we need one digit less as we recurse
output);
int main(int argc, _TCHAR* argv[])
const int nToChooseFrom = 5;
const int nToChooose = 3;
const int input[nToChooseFrom] = 6, 7, 8, 9, 10 ; // provide input in sorted order (or sort it!)
intvecs output;
GenerateUnOrderedIntVecs(
input, nToChooseFrom,
intvec(), nToChooose,
output);
for(intvecs::const_iterator i=output.begin(); i!=output.end(); ++i)
std::cout << "[ ";
const intvec& unordered_tuple = *i;
for(intvec::const_iterator j = unordered_tuple.begin(); j!=unordered_tuple.end(); ++j)
std::cout << *j << " ";
std::cout << "]\n";
return 0;
这似乎适用于你的两个例子(但我只彻底检查了第一个)。如果您无法通过阅读代码来了解它是如何工作的,那么一个好的方法是在调试器中运行它(这是我必须做的才能让它工作!:)
【讨论】:
以上是关于生成具有指定条目长度重复的有序选择的主要内容,如果未能解决你的问题,请参考以下文章