动态迭代编程生成组合

2024-01-25

用我自己的程序版本更新:

我正在尝试进行迭代动态编程来生成n choose k组合。

假设我有 4 个值向量

v1 : 1 1 1
v2 : 2 2 2
v3 : 3 3 3
v4 : 4 4 4

现在我使用加法作为我的聚合函数,我想生成4 choose 2向量组合如下:

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 and 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 : Table1

我们可以找N choose k通过以下方式使用动态程序进行组合:

方法如下:

  1. Block[0,1] 和 Block[0,2] 始终返回 [ ]。 {[ ] 表示空值,因为那里没有值}。
  2. Block[1,1] 接收 [ ],计算 {v1} + [ ] (即 v1 本身),并将其保存到 Block [1,1]。
  3. Block[1,2] 接收 [ ],执行 {v1} + [ ] & {v2} + [ ],将其保存到 Block [1,2]。
  4. Block[1,3] 接收 [ ],执行 {v1} + [ ]、{v2} + [ ] + {v3} U [ ]、Block [1,3]。
  5. Block[2,4] receives :
    • [{v1}] 来自 [1,1] 并计算 {v1} + {v2},
    • [{v1}{v2}] 来自 [1,2] 并计算 {v1} + {v3} 和 {v2} + {v3}
    • [{v1}, {v2}, {v3}] 从 [1,3] 计算 {v4} + {v1}, {v4} + {v2} 和 {v4} + {v3},将其保存到 Block [ 2,4]。

现在我们在块 [2,4] 中拥有了所需的所有值。我如何用 C++ 有效地编写这个概念?

任何帮助是极大的赞赏。谢谢。

这是我的想法:

我不知道这是否正确。对不起

=================================================== =======

//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;
}

=================================================== =======

这是我针对上述算法的程序:

#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 ); 

}

如果您运行该程序,您就会知道我想要实现什么以及以何种方式实现。这个算法(不是程序)对于较少数量的向量可能效率不高,但当 N > 50k 和 k ~ 10 时就会有效。我知道算法(我的程序)的实现效率非常低。有什么办法可以改善吗?我认为相同的算法可以以更优雅的方式实现。任何帮助深表感谢。谢谢。


对于之前误解您的答案,我深表歉意,我真的不明白您在帖子中想要做什么,我以为您只是在寻找计算 nCk 的非递归方式:P

我创建了一个类,CombinationGenerator产生向量的组合,我相信这就是你想要的。它的工作原理是生成一个整数向量,表示要聚合的元素的索引(我已经包含了main下面的函数应该有助于以编程方式解释它)。

这是头文件:http://pastebin.com/F5x4WKD9 http://pastebin.com/F5x4WKD9

以及源文件:http://pastebin.com/CTV1PLRb http://pastebin.com/CTV1PLRb

这是一个示例主函数:

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:

有 50,000 个向量,每个向量包含 3 个整数(让我们假设每个 32 字节向量的开销相当严重,在大多数实现中通常约为 20):因此,(50,000 * 3 * 4) + (50,000 * 32) = 2,200,000 Bytes

然后将其包含在双端队列中,我们还假设它的开销为 32 字节:2,200,000 + 32 = 2,200,032 Bytes

我们还有一个运行组合生成器的实例,它有 5 个成员变量、两个 int、两个 long long 和一个包含 k 个 int(在本例中为 1000)的向量,因此:2,200,032 + (2*4) + (2*8) + (1000*4) + 32 = 2,204,056 Bytes

我们还有包含 k 个整数的每次迭代结果的向量:2,204,056 + (1000*4) + 32 = 2,208,088 Bytes

正如您所看到的,这远远低于您的 4GB 内存。注意:无论您使用什么实现,都不可能将这些向量中的每一个存储在内存中,因为将会超过9.94 x 10^2126包含结果的向量。即使您选择较小的 k 值(例如 10),您仍然会得到超过2.69 x 10^40.

我希望这次我明白你的要求是什么!如果没有,我会尝试再次理解您想要实现的目标。 :)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态迭代编程生成组合 的相关文章

  • 使用 CMake 时如何导出 Emscripten 中的 C 函数

    In 本教程 https emscripten org docs porting connecting cpp and javascript Interacting with code html interacting with code
  • 循环遍历 C 结构中的元素以提取单个元素的值和数据类型

    我有一个要求 我有一个 C 语言的大结构 由大约 30 多个不同数据类型的不同元素组成 typedef struct type1 element1 type2 element2 type3 element3 type2 element4 1
  • 当事件button.click发生时,如何获取按钮名称/标签?

    我以编程方式制作按钮并将它们添加到堆栈面板中 以便每次用户导航到页面时按钮都会发生变化 我正在尝试做这样的事情 当我单击创建的按钮时 它将获取按钮的标签并转到正确的页面 但是 我无法使用 RoutedEventHandler 访问按钮元素
  • 无法注册时间触发的后台任务

    对于 Windows 8 应用程序 在 C Xaml 中 我尝试注册后台任务 很难说 但我想我的后台任务已正确注册 但是当我单击调试位置工具栏上的后台任务名称时 我的应用程序停止工作 没有任何消息 我查看了事件查看器上的日志 得到 具有入口
  • cpp.react库的C++源代码中奇怪的“->* []”表达式

    这是我在文档中找到的 C 片段cpp react 库 https github com schlangster cpp react implicit parallelism auto in D MakeVar 0 auto op1 in g
  • Eigen 和 OpenMP:由于错误共享和线程开销而没有并行化

    系统规格 Intel Xeon E7 v3 处理器 4 插槽 16 核 插槽 2 线程 核心 Eigen 系列和 C 的使用 以下是代码片段的串行实现 Eigen VectorXd get Row const int j const int
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • 在 C# 中检查 PowerShell 执行策略的最佳方法是什么?

    当你跑步时Get ExecutionPolicy在 PowerShell 中 它得到有效的执行政策 https learn microsoft com en us powershell module microsoft powershell
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 不可变类与结构

    以下是类与 C 中的结构的唯一区别 如果我错了 请纠正我 类变量是引用 而结构变量是值 因此在赋值和参数传递中复制结构的整个值 类变量是存储在堆栈上的指针 指向堆上的内存 而结构变量作为值存储在堆上 假设我有一个不可变的结构 该结构的字段一
  • 将函数参数类型提取为参数包

    这是一个后续问题 解包 元组以调用匹配的函数指针 https stackoverflow com questions 7858817 unpacking a tuple to call a matching function pointer
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • 如何解压 msgpack 文件?

    我正在将 msgpack 编码的数据写入文件 在编写时 我只是使用 C API 的 fbuffer 如 我为示例删除了所有错误处理 FILE fp fopen filename ab msgpack packer pk msgpack pa
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • Visual Studio 2015 - Web 项目上缺少共享项目参考选项卡

    我从 MSDN 订阅升级到 Visual Studio 2015 因为我非常兴奋地阅读有关共享项目的信息 当我们想要做的只是重用代码时 不再需要在依赖项中管理 21382 个 nuget 包 所以我构建了一个测试共享项目 其中包含一些代码
  • 了解 Lambda 表达式和委托 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经尝试解决这个问题很长一段时间了 阅读在线博客和文章 但到目前为止还没有成功 什么是代表 什么是 Lambda 表达式 两者的优点
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我
  • 没有“对 *this”功能的右值引用的解决方法

    我有一个围绕可移动对象的代理容器类 并希望代理能够隐式生成对底层对象的右值引用 但仅当代理本身被移动时 我相信我将能够按照提案 n2439 实施此行为 将移动语义扩展到 this http www open std org jtc1 sc2
  • 为什么空循环使用如此多的处理器时间?

    如果我的代码中有一个空的 while 循环 例如 while true 它将把处理器的使用率提高到大约 25 但是 如果我执行以下操作 while true Sleep 1 它只会使用大约1 那么这是为什么呢 更新 感谢所有精彩的回复 但我

随机推荐