问题描述
更新为我自己的程式版本:
Updated with my own version of the program :
我想要执行迭代动态程式来产生 n选择k
组合。
I'm trying to do an iterative dynamic programming to generate n choose k
combination.
说我有4个值的向量
v1 : 1 1 1
v2 : 2 2 2
v3 : 3 3 3
v4 : 4 4 4
$ b b
现在我使用加法作为我的聚合函数,我想要生成 4选择2
向量的组合如下:
Now I use addition as my aggregate function and I want to generate 4 choose 2
combinations of vectors as follows :
v1v2 : 3 3 3
v1v3 : 4 4 4
v1v4 : 5 5 5
v2v3 : 5 5 5
v2v4 : 6 6 6
v3v4 : 7 7 7
这将是通过每对,找到结果。如果 N
和 k
非常大,这是非常低效的。因此,一种替代方法是递归/迭代动态规划。对于非常大的N和k的递归将占用大量的存储器,所以理想的方式是迭代动态规划,其可以如下进行:
A naive way to do this would be to go through every pair and find the result. if the N
and k
are very large this is very very inefficient. So an alternative way to this would be recursive/iterative dynamic programming. Recursion for very large N and k would take up a lot of memory so the ideal way to this would be iterative dynamic programming which can be done as follows :
考虑以下表行头是 N
,列标题是 k
,我们的目标是找到 N选择k
:
Consider the following table row header is N
and the column header is k
and our objective is to find N choose k
:
我们可以使用动态程序通过以下方式找到 N choose k
组合:
We can find N choose k
combination using dynamic program by following way :
方法如下:
- 阻止[0,1]和阻止[0,2]总是返回[]。
- 阻止[1,1]接收[],计算{v1} + [](它本身是v1本身)
- 阻止[1,2]接收[],执行{v1} + []&
- 阻止[1,3]接收[],执行{v1} + [],{v2} + [] + {v3} U [],封锁[1,3]。
- 封锁[2,4]来自[1,1]并计算{v1} + {v2},
- [{v1} {v2}来自[1,3]的{v3}和{v2} + {v3}和{v2} + {v3}
- Block[0,1] and Block[0,2] always returns [ ]. {[ ] denotes an empty value as there are no values there}.
- Block[1,1] receives [ ], computes {v1} + [ ] (which is v1 itself) , saves it to Block [1,1].
- Block[1,2] receives [ ], does {v1} + [ ] & {v2} + [ ], saves it to Block [1,2].
- Block[1,3] receives [ ], does {v1} + [ ], {v2} + [ ] + {v3} U [ ], Block [1,3].
- Block[2,4] receives :
- [{v1}] from [1,1] and computes {v1} + {v2},
- [{v1}{v2}] from [1,2] and computes {v1} + {v3} and {v2} + {v3}
- [{v1}, {v2}, {v3}] from [1,3] and computes {v4} + {v1}, {v4} + {v2} and {v4} + {v3}, saves it to Block [2,4].
现在我们拥有Block [2,4]中需要的所有值。我怎么能在C ++中有效地编码这个概念?
Now we have all the values we need in Block [2,4]. how can i code this concept efficiently in C++ ?
任何帮助都非常感谢。非常感谢。
Any help is greatly appreciated. Thanks.
这是我的想法:
我不知道这是否正确。对不起,
I don't know if this is right. Sorry
============================== =====================
=========================================================
//Block [0...k][0...n];
//Block[i][j] contains i-set groups (for eg :if i = 2 it will have v1v2, v1v3, etc..)
//initially, Block[0][i] = [ ] for 0 <= i <= n and all other Block [i][j] = [ $ ]
// "$" is just a symbol to indicate that no computation is done on that block
algorithm(int k, int n) //k-point skyline groups from n number of points.
{
if( Block[k][n] != [ $ ] ) return memory[k][n];
Group = [ ]; //G indicate a collection of vectors
for( int i = k; i <= n; i++ )
{
Group` = algorithm(k-1, i-1);
for( each v` in Group` )
{
Group = Group + (group` + v_i);
}
}
memory[k][n] = Group;
return Group;
}
================ =====================================
=========================================================
这是我上面提到的算法的程序:
Here is my program for the above mentioned algorithm :
#include <iostream>
#include <iterator>
#include <set>
#include <vector>
#include <map>
#define DIMENSIONS 5 // No. of elements in the vector. eg. v1: 1 1 1 1 1
using namespace std;
typedef std::set < int > my_set; // To hold vector id's
typedef std::vector < int > my_vector; // To hold values of the vector's
typedef std::vector < std::pair < my_set, my_vector > > my_vector_pair;
typedef std::map < my_set, my_vector > my_map;
typedef std::vector < vector < std::pair < int,my_map > > > my_pair;
typedef my_map::iterator m_it;
my_vector_pair bases; // To hold all the initial <id,vector_values> pair
my_map data, G;
my_pair memory;
void print(my_map& data)
{
for( m_it it(data.begin()) ; it!=data.end(); ++it)
{
cout << "Id : ";
copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
cout << " => value : ";
copy (it->second.begin(),it->second.end(),ostream_iterator<int>(cout," "));
cout << endl;
}
cout << "---------------------------------------------------------------\n";
}
my_map union_(my_map& G, int p)
{
static my_map result;
my_set id;
my_vector scores;
result.clear();
for (m_it it(G.begin()); it != G.end(); ++it)
{
id = it->first;
scores = it->second;
id.insert( bases.at(p-1).first.begin(),bases.at(p-1).first.end() );
for (int j = 0; j < DIMENSIONS; j++)
{
scores.at(j) += bases.at(p - 1).second.at(j);
}
result.insert(make_pair(id, scores));
}
return result;
}
my_map algorithm_(int k, int n) {
unsigned long size = memory.at(n).size();
for (unsigned long i = 0; i < size; i++) {
if (memory.at(n).at(i).first == k) {
return memory.at(n).at(i).second; //if exists in hash table then no need to calculate again
}
}
my_map G_k_1;
if (k != n)
{
G_k_1 = algorithm_(k, n - 1);
if(G_k_1.size() == 0)
{
return G_k_1;
}
}
G_k_1 = algorithm_(k - 1, n - 1);
if(G_k_1.size() == 0)
{
return G_k_1;
}
G_k_1 = union_(G_k_1, n);
if (k != n) {
for (unsigned long i = 0; i < memory.at(n - 1).size(); i++) {
if (memory.at(n - 1).at(i).first == k) {
G_k_1.insert(memory.at(n - 1).at(i).second.begin(), memory.at(n - 1).at(i).second.end());
memory.at(n - 1).at(i).second.clear();
break;
}
}
}
std::pair<int,my_map> temp;
temp.first = k ;
temp.second = G_k_1;
memory.at(n).push_back( temp ); //storing in hash table for further use
return memory.at(n).back().second;
}
int main()
{
my_vector v1,v2,v3,v4,v5;
my_set s1,s2,s3,s4,s5;
for(int i = 1; i<=5; ++i)
{
v1.push_back(1);
v2.push_back(2);
v3.push_back(3);
v4.push_back(4);
v5.push_back(5);
}
s1.insert(1);
s2.insert(2);
s3.insert(3);
s4.insert(4);
s5.insert(5);
bases.insert(bases.end(),make_pair(s1,v1));
bases.insert(bases.end(),make_pair(s2,v2));
bases.insert(bases.end(),make_pair(s3,v3));
bases.insert(bases.end(),make_pair(s4,v4));
bases.insert(bases.end(),make_pair(s5,v5));
my_set empty_set;
my_vector empty_group(DIMENSIONS);
G.insert(make_pair(empty_set,empty_group));
vector<std::pair<int,my_map> > empty_element;
empty_element.push_back(make_pair(0,G));
for (int i = 0; i <= 5; i++) { // 5 is the total number od vectors : v1,v2,v3,v4,v5
memory.push_back(empty_element);
}
data.insert(bases.begin(),bases.end());
cout << endl << "The intial set of vectors are : " << endl;
print ( data );
int k;
cout << "N = 5 " << endl << "Enter the value of k : ";
cin >> k;
cout << "The values for N choose k are : " << endl;
data = algorithm_(k,5);
print ( data );
}
如果运行程序,并以什么方式。这个ALGORITHM(不是程序)对于较小数量的向量可能不是有效的,但是当N> 50k和k〜10时将是有效的。我知道算法的执行(我的程序)是非常低效的。有什么办法改善吗?我认为相同的算法可以以更优雅的方式实现。任何帮助是非常赞赏。感谢。
If you run the program you know what I wanted to achieve and in what way. This ALGORITHM (not program) might not be efficient for a smaller number of vectors but it will be when N > 50k and k ~ 10. I'm aware the implementation of the algorithm (my program) is very inefficient. Is there any way to improve it ? I think the same algorithm can be implemented in a much more elegant fashion. Any help is much appreciated. Thanks.
推荐答案
我对以前误解您的答案道歉,我不太明白您在自己的帖子中做了什么,我想你只是寻找一个非递归的计算nCk的方法:P
My apologies for misunderstanding your answer previously, I didn't really understand what you were trying to do in your post, I thought you were just looking for a non-recursive way of computing nCk :P
我创建了一个类, CombinationGenerator
生成向量的组合,我相信是你想要的。它的工作原理是通过生成一个表示要聚合的元素的索引的ints的向量(我已经包括一个 main
函数下面应该有助于以编程方式解释它)。
I've created a class, CombinationGenerator
to produce the combinations of vectors, which I believe is what you want. It works by producing a vector of ints representing the indices of the elements to aggregate (I've included a main
function below which should help to explain it programmatically).
以下是头文件:
和源文件:
这里是一个主要功能示例:
And here is a sample main function:
typedef std::vector<int> vecInt;
int main() {
// We have a deque containing 3 elements (try using experimenting with data
// types to test space complexity, std::set or std::unordered_set might be an option)
vecInt vec1;
for( int i = 0; i < 3; i++ )
{
vec1.push_back(1);
}
vecInt vec2;
for( int i = 0; i < 3; i++ )
{
vec2.push_back(2);
}
vecInt vec3;
for( int i = 0; i < 3; i++ )
{
vec3.push_back(3);
}
vecInt vec4;
for( int i = 0; i < 3; i++ )
{
vec4.push_back(4);
}
vecInt vec5;
for( int i = 0; i < 3; i++ )
{
vec5.push_back(5);
}
std::deque<std::vector<int>> dequeVecs;
dequeVecs.push_back( vec1 );
dequeVecs.push_back( vec2 );
dequeVecs.push_back( vec3 );
dequeVecs.push_back( vec4 );
dequeVecs.push_back( vec5 );
// Create our CombinationGenerator:
CombinationGenerator* gen = new CombinationGenerator();
g_pCombinationGen = gen;
gen = NULL;
unsigned long long size = g_pCombinationGen->ComputeBinomialCoefficient( dequeVecs.size(), 2 );
std::vector<int> currCombination;
g_pCombinationGen->Initialize( dequeVecs.size(), 2, size );
while( !g_pCombinationGen->IsFinished() )
{
currCombination = g_pCombinationGen->NextCombination();
std::vector<int> result;
for( int i = 0; i < dequeVecs[0].size(); i++ )
{
result.push_back( dequeVecs[currCombination[0]][i] + dequeVecs[currCombination[1]][i] );
}
std::cout << "(";
for( int i = 0; i < result.size(); i++ )
{
std::cout << result[i];
}
std::cout << ")" << std::endl;
}
return 0;
}
虽然这可能看起来相当大,使用它(让我们假设你使用n = 50,000和k = 1000:
Whilst this may look rather large, if you analyze the space usage of it (let's assume that you're using n = 50,000 and k = 1000:
有50,000个向量,每个包含3个int向量的32bytes,它通常在大多数实现上约20):所以,(50,000 * 3 * 4)+(50,000 * 32)= 2,200,000字节
There are 50,000 vectors each containing 3 ints (let's assume a reasonably harsh overhead per vector of 32bytes, it's normally around 20 on most implementations): So, (50,000 * 3 * 4) + (50,000 * 32) = 2,200,000 Bytes
然后你将这个包含在deque中,我们也假设它的开销为32bytes: 2,200,000 + 32 = 2,200,032 Bytes
You're then containing this in a deque, which we will also assume has an overhead of 32bytes: 2,200,000 + 32 = 2,200,032 Bytes
我们还有一个运行Combination Generator的实例,它有5个成员变量,两个int,两个长longs和一个包含k ints的向量1000),因此: 2,200,032 +(2 * 4)+(2 * 8)+(1000 * 4)+32 = 2,204,056 Bytes
We're also having an instance running of the Combination Generator, this has 5 member variables, two ints, two long longs, and a vector containing k ints (in this case 1000), so: 2,200,032 + (2*4) + (2*8) + (1000*4) + 32 = 2,204,056 Bytes
我们还有一个包含每次迭代的结果的向量,再次使用k ints: 2,204,056 +(1000 * 4)+ 32 = 2,208,088 Bytes
We also have the vector containing the result for each iteration again with k ints: 2,204,056 + (1000*4) + 32 = 2,208,088 Bytes
正如你所看到的,这远远低于你的4GB内存。注意:不管你使用什么实现,都不可能将这些向量存储在内存中,因为会有 9.94 x 10 ^ 2126
个包含结果的向量。即使你选择了小的k值,例如10,你仍然会有 2.69 x 10 ^ 40
。
As you can see, this is far below your 4GB of memory. NOTE: It would not be possible to store each of these vectors in memory regardless of what implementation you used, as there would be over 9.94 x 10^2126
vectors containing results. Even if you chose a small value of k such as 10, you would still have over 2.69 x 10^40
.
我希望这一次我明白你要的是什么!如果没有,我会再次尝试,再次明白你想要达到什么。 :)
I hope this time I've understood what it is you're asking for! If not, I'll try and understand again what it is you're trying to achieve. :)
这篇关于动态迭代编程生成组合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!