【问题标题】:Print All Subvector Combinations + Issue打印所有子向量组合 + 问题
【发布时间】:2016-01-24 01:28:07
【问题描述】:

我正在尝试创建一个工具,让我的生活更轻松,以便根据数字加法设置配置设置列表,以指示应启用哪些功能。我正在使用从 1 到 512 (1,2,4,8,16,32,64,128,256,512) 的 2 幂列表。

手动检查并创建一个列表,列出哪些值将启用哪些功能会非常耗时,因此我尝试以编程方式执行此操作,然后将输出保存到文件中。但是,我在寻找合适的解决方案时遇到了问题。

我已经阅读了来自 SO 和其他编码论坛的几乎所有问题,这些问题在 Google 中出现,并且都涉及线性组合。这是我能够做到的,并且我有这个示例代码,我对其进行了更改,然后在以下基础上构建了我的工具:

    #include <iostream>
using std::cout;
using std::cin;
using std::endl;

// A is the array that contains the numbers
// comb is an array of size k that will hold all possible combinations
// n is the size of input array
// k is 1 less than the size of combination i.e. we want to find out 4C2 k =1
// current_k is the variable that makes us simulates k loops in a recursive function
void combinations(int A[], int comb[], int start, int n, int current_k, int k){
    int sum = 0;

    if (k < 0)
        return;

    // Base case just print all the numbers 1 at a time
    if (k == 0){
        for (int i = 0; i < n; i++)
            cout << A[i] << endl;
    }

    // current_k goes from 0 to k-1 and simulates a total of 
    // k iterations
    if (current_k < k){
        // if current_k = 0, and k = 3 (i.e. we need to find combinations of 4) 
        // then we need to leave out 3 numbers from the end because there are 3
        // more nested loops
        for (int i = start; i < n - (k - current_k); i++){
            // Store the number in the comb array and recursively call with the remaining sub-array
            comb[current_k] = A[i];
            // This will basically pass a sub array starting at index 'start' and going till n-1
            combinations(A, comb, i+1, n, current_k+1, k);
        }
    }

    else if (current_k == k){
        for (int i = start; i < n; i++){
            comb[current_k] = A[i];

            for (int j = 0; j <= k; j++){
                sum += comb[j];     
            }
            
            cout << sum << endl;
            sum = 0;
        }
    }

    else
        return;
}

int main(){
    int n;
    cout << "Enter the 'n' " << endl;
    cin >> n;
    int *A = new int[n];

    for (int i = 0; i < n; i++)
        A[i] = i+1;

    int k;
    cout << "Enter 'k'" << endl;
    cin >> k;
    int *comb = new int[k];

    combinations(A, comb, 0, n, 0, k-1);

    system("pause");
    return 0;
}

唯一的问题是我还需要非线性组合。像 1+64+256 这样的东西。这也能捡起这些组合吗?而且我也有一个问题,我将在发布代码后进行解释。这是我为此使用的实际代码:

#include <iostream>
#include <vector>
#include <string>
#include "mcl.h"

using std::cout;
using std::vector;
using std::string;
using std::cin;
using std::endl;

static vector<string> results;

// A is the array that contains the numbers
// comb is an array of size k that will hold all possible combinations
// n is the size of input array
// k is 1 less than the size of combination i.e. we want to find out 4C2 k =1
// current_k is the variable that makes us simulates k loops in a recursive function
void combinations(vector<mcl> A, vector<mcl> comb, int start, int n, int current_k, int k){
    string sum;
    string sNames;
    int sCodes = 0;

    if (k < 0)
        k = 0;

    // Base case just print all the numbers 1 at a time
    if (k == 0){
        for (int i = 0; i < n; i++)
            cout << A.at(i).getCode() << " - " << A.at(i).getName() << endl;
        return;
    }

    // current_k goes from 0 to k-1 and simulates a total of 
    // k iterations
    if (current_k < k){
        // if current_k = 0, and k = 3 (i.e. we need to find combinations of 4) 
        // then we need to leave out 3 numbers from the end because there are 3
        // more nested loops
        for (int i = start; i < n - (k - current_k); i++){
            // Store the number in the comb array and recursively call with the remaining sub-array
            comb.push_back(mcl(A.at(i).getCode(),A.at(i).getName()));
            // This will basically pass a sub array starting at index 'start' and going till n-1
            combinations(A, comb, i + 1, n, current_k + 1, k);
        }
    }

    else if (current_k == k){
        for (int i = start; i < n; i++){
            comb.at(current_k-1) = A.at(i);

            for (int j = 0; j < k; j++){
                sCodes += comb.at(j).getCode();
                if (sNames != ""){
                    sNames = sNames + "," + comb.at(j).getName();
                }

                else{
                    sNames = sNames + comb.at(j).getName();
                }
            }
        }

        results.push_back(sCodes + " - " + sNames);
        sCodes = 0;
        sNames = "";
    }

    else
        return;
}

int main(){
    int k;
    vector<mcl> A,comb;

    A.push_back(mcl(1, "Light"));
    A.push_back(mcl(2, "Bright"));
    A.push_back(mcl(4, "Dark"));

    k = 2;
    

    combinations(A, comb, 0, A.size(), 0, k - 1);

    //system("cls");
    for (int i1 = 0; i1 < results.size(); i1++){
        cout << results.at(i1) << endl;
    }

    system("pause");
    return 0;
}

mcl头和imp代码:

#ifndef MCL_H
#define MCL_H

#include <string>

using std::string;

class mcl{
public:
    mcl(int code, string name);

    int getCode();
    string getName();

    void setCode(int i);
    void setName(string s);

private:
    int cCode;
    string cName;
};
#endif;

小鬼:

#include "mcl.h";

mcl::mcl(int code, string name){
    cCode = code;
    cName = name;
}

int mcl::getCode(){
    return cCode;
}

string mcl::getName(){
    return cName;
}

void mcl::setCode(int i){
    cCode = i;
}

void mcl::setName(string s){
    cName = s;
}

现在讨论这个问题。当我尝试测试我在代码中定义的三个 mcl 对象的组合的显示时,我看到了这个输出:

明暗

,黑暗

按任意键继续。 . .

如果我将 k 设置为 0,我会看到每个单独对象的数据都正确显示:

1 - 光

2 - 明亮

4 - 黑暗

按任意键继续。 . .

我认为这个问题是由创建结果向量以供显示的 for 循环引起的,但我不确定实际问题是什么。

作为我预期输出的示例,鉴于上面代码中的硬编码元素,这是我试图让工具输出的内容(其中粗体是基本设置,非粗体是组合):

1 - 光
2 - 明亮
3 - 亮,亮
4 - 暗
5 - 浅色,深色
6 - 明亮,黑暗
7 - 光、亮、暗

【问题讨论】:

    标签: c++ vector combinatorics


    【解决方案1】:

    看了你的代码一段时间后;并试图理解你在组合函数中找到的这部分代码引起了我的注意:

        else if ( current_k == k ) {
            for ( int i = start; i < n; i++ ) {
                comb.at(current_k-1) = A.at(i);
    
                for ( int j = 0; j < k; j++ ){
                    sCodes += comb.at(j).getCode();
                    if ( sNames != "" ) {
                        sNames = sNames + "," + comb.at(j).getName();
    
                    } else {
                        sNames = sNames + comb.at(j).getName();
                    }
                }
            }
    
            results.push_back(sCodes + " - " + sNames);
            sCodes = 0;
            sNames = "";
    
        } else {
            return;
        }
    

    我在这里的想法是你正在经历一个双 for 循环,并且在双 for 循环完成之前你不会更新你的向量。这是你想要的吗?还是您的意思是在内部 for 循环的每次迭代后保存? If So 那么你只需要在你的 if else 语句之后将它移动到内部 for 循环的内部,修改后的代码如下所示:

        else if ( current_k == k ) {
            for ( int i = start; i < n; i++ ) {
                comb.at(current_k-1) = A.at(i);
    
                for ( int j = 0; j < k; j++ ){
                    sCodes += comb.at(j).getCode();
                    if ( sNames != "" ) {
                        sNames = sNames + "," + comb.at(j).getName();
    
                    } else {
                        sNames = sNames + comb.at(j).getName();
                    }
    
                    results.push_back(sCodes + " - " + sNames);
                }
            }
    
            sCodes = 0;
            sNames = "";
    
        } else {
            return;
        }
    

    如果这对您有任何帮助,请告诉我;不幸的是,我没有时间尝试在我的 IDE 中重新创建您的代码来尝试编译、构建、运行和调试,以查看修改后版本的输出是否正确。我是从头顶视觉上做的。如果我在不久的将来有空闲时间;我也许可以这样做,并尝试看看我能想出什么。

    【讨论】:

    • 我尝试了这个,但除了在结果向量中添加了一个额外的元素外,它并没有太大变化。我试图做的是得到这样的输出给定代码中的硬编码元素:1 - 亮 2 - 亮 3 - 亮,亮 4 - 暗 5 - 亮,暗 6 - 亮,暗 7 - 亮,明亮,黑暗
    • 是的,我尝试阅读您的代码,我有点理解您要做什么;但是您的算法很难解决。也许在几天后;我必须将您的代码复制到我的 IDE 中并对其进行处理,以查看调试器中发生了什么,以便为您提供更多见解。
    【解决方案2】:

    因此,经过大量研究和测试后,我决定这对我的情况并不适用,而且在性能方面成本太高。相反,我通过一个中间表选择数据库内 (SQLite) 解决方案,该中间表将以一对多关系将一个表中的 ID 映射到另一个表中的 ID。与上面示例尝试做的通过代码处理所有事情的蛮力方法相比,更容易编写代码并且性能非常简单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-24
      • 1970-01-01
      • 1970-01-01
      • 2021-10-27
      • 2017-08-24
      相关资源
      最近更新 更多