【问题标题】:Algorithm to get Cartesian product获得笛卡尔积的算法
【发布时间】:2015-10-21 04:46:29
【问题描述】:

我有一个像[0,2,3,0,1] 这样的数组作为输入,我需要找到{0}x{0,1,2}x{0,1,2,3}x{0}x{0,1} 的笛卡尔积,更准确地说我需要输出如下。


输入:

[0, 2, 3, 0, 1]

输出:

[0, 0, 0, 0, 0]
[0, 0, 0, 0, 1]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 1]
[0, 0, 2, 0, 0]
[0, 0, 2, 0, 1]
[0, 0, 3, 0, 0]
[0, 0, 3, 0, 1]
[0, 1, 0, 0, 0]
[0, 1, 0, 0, 1]
[0, 1, 1, 0, 0]
[0, 1, 1, 0, 1]
[0, 1, 2, 0, 0]
[0, 1, 2, 0, 1]
[0, 1, 3, 0, 0]
[0, 1, 3, 0, 1]
[0, 2, 0, 0, 0]
[0, 2, 0, 0, 1]
[0, 2, 1, 0, 0]
[0, 2, 1, 0, 1]
[0, 2, 2, 0, 0]
[0, 2, 2, 0, 1]
[0, 2, 3, 0, 0]
[0, 2, 3, 0, 1]

我需要一个通用算法。任何想法 ?我想用 C++ 编写它。 谢谢

【问题讨论】:

标签: c++ arrays algorithm cartesian-product


【解决方案1】:

硬编码解决方案是:

for (int a1 : {0}) {
  for (int a2 : {0,1,2}) {
    for (int a3 : {0,1,2,3}) {
      for (int a4 : {0}) {
        for (int a5 : {0,1}) {
            do_job(a1, a2, a3, a4, a5);
        }
      }
    }
  }
}

您可以使用以下通用方式(将所有as 放入向量中):

bool increase(const std::vector<std::size_t>& v, std::vector<std::size_t>& it)
{
    for (std::size_t i = 0, size = it.size(); i != size; ++i) {
        const std::size_t index = size - 1 - i;
        ++it[index];
        if (it[index] > v[index]) {
            it[index] = 0;
        } else {
            return true;
        }
    }
    return false;
}

void iterate(const std::vector<std::size_t>& v)
{
    std::vector<std::size_t> it(v.size(), 0);

    do {
        do_job(it);
    } while (increase(v, it));
}

Live Demo

【讨论】:

    【解决方案2】:

    从您的示例中,您似乎想使用混合基数进行计数,而您的输入是每个位置的最大数字值。

    一个简单的方法是使用算术编码,特殊处理最大数字 0 的位置。这是最大位数不为 0 的情况的伪代码:

    input radixes
    let n_numbers = product_of radixes
    for i = 0 to n_numbers-1 inclusive
        let n = i
        for digit_pos = 0 to number-of-radixes-1
            output n mod radix[digit_pos]
            let n = n div radix[digit_pos]
        output newline
    

    我将 0 作为最大数字的处理保留在一个位置,作为练习。 :)


    我不记得在 C++ 标准库中对此有任何特别相关的支持。 IE。它主要是一个与语言无关的问题,与 C++ 无关,与排列无关,与数组无关。如果我对它的解释是正确的:最好也用文字来描述问题,而不仅仅是一个例子。

    【讨论】:

    • 0 作为最大位数没有特殊情况:-)
    【解决方案3】:

    递归似乎是解决此问题的最简单方法,因为您可能不知道输入向量的长度。像这样的:

    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class Cartesian {
    
      public static void printCartesian(String head, ArrayList<Integer> array) {
        if (array.size() == 0) {
          System.out.println(head);
          return;
        }
        if (array.size() == 1) {
          for (int i = 0; i <= array.get(0); ++i) {
            System.out.println(head + i + "]");
          }
          return;
        }
        // assert array.size() > 1
        int a0 = array.get(0);
        ArrayList<Integer> array0 = new ArrayList<Integer>(array);
        array0.remove(0);
        for (int i = 0; i <= a0; ++i) {
          printCartesian(head + i + ", ", array0);
        }
      }
    
      public static void main(String[] args) {
        Integer[] input = { 0, 2, 3, 0, 1 };
        ArrayList<Integer> array = new ArrayList<Integer>(Arrays.asList(input));
        printCartesian("[", array);
      }
    }
    

    初始调用是printCartesian("[", a),其中a 是一个ArrayList,其中包含按顺序排列的数组元素。必须为size == 1 添加一个额外的if 子句,否则会打印太多逗号。

    将其转换为 C++ 数据结构应该不难。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-03
      • 2018-02-03
      • 2011-03-24
      • 2017-03-07
      • 1970-01-01
      • 2015-07-29
      • 2023-02-19
      • 2013-10-22
      相关资源
      最近更新 更多