从N个列表中选择数字的计数方法

Counting ways to select numbers from N lists

本文关键字:方法 数字 选择 列表      更新时间:2023-10-16

给定N个从1到100的列表

我想要选择数字的方法的数量,从每个不同的列表中选择一个,而不允许重复。

注意:如果选择的数字不同,则两种方式不同。

示例:

List 1 : 5, 100, 1
List 2 : 2
List 3 : 5, 100
List 4 : 2, 5, 100

因为我想从每个数字中选择1个数字,而不重复。

在这种情况下答案将是:2(1,2,5,100和1,2,100,5)。

我的方法:我尝试用包容和排斥的原则来解决它。但是如何找到所有的交叉点呢?

我在想,在一个集合中取列表,在另一个集合中取对应的映射数,可以用匹配来解决吗?

N最大可达10,每个列表的数字可以在1-100之间。

这是@robertking算法的一个实现

指出:

  • 使用std::vector<bool>存储已经使用的数字(在大多数STL实现中都优化了将bool存储为位)。
  • 使用cache变量(动态规划)加速先前获得结果的大搜索。
  • 使用TRACE定义打印或不打印溶液

代码(在GCC 4.9.0和Windows下的c++ 11中测试):

#include <iostream>
#include <bitset>
#include <vector>
#include <map>
#define TRACE
typedef std::vector<bool> used_numbers_t;
typedef std::vector<int> list_t;
typedef std::vector<list_t> lists_t;
typedef std::map<std::pair<used_numbers_t, unsigned int>, int> cache_t;
cache_t cache;
long solve(used_numbers_t& used_numbers, const lists_t& lists, list_t& generated_solution, unsigned int list_idx = 0, int solutions = 0) {
    if (list_idx == lists.size()) {
#ifdef TRACE
        for (auto gs : generated_solution) {
            std::cout << gs << ",";
        }
        std::cout << std::endl;
#endif
        return solutions + 1;
    }
    auto key = std::make_pair(used_numbers, list_idx);
    auto it = cache.find(key);
    if (it != cache.cend()) {
        return it->second;
    }
    long actual_solutions = 0;
    auto& processing_list = lists[list_idx];
    for (unsigned int idx = 0; idx < processing_list.size(); idx++) {
        if (!used_numbers[processing_list[idx] - 1]) {
            used_numbers[processing_list[idx] - 1] = true;
#ifdef TRACE
            generated_solution.push_back(processing_list[idx]);
#endif
            actual_solutions += solve(used_numbers, lists, generated_solution, list_idx + 1, solutions);
#ifdef TRACE
            generated_solution.pop_back();
#endif
            used_numbers[processing_list[idx] - 1] = false;
        }
    }
    cache.insert(std::make_pair(key, actual_solutions));
    return solutions + actual_solutions;
}
int main(int argc, char* argv[]) {
    lists_t lists{{5, 100, 1}, {2}, {5, 100}, {2, 5, 100}};
    used_numbers_t used_numbers(100);
    list_t generated_solution;
    long solutions = solve(used_numbers, lists, generated_solution);
    std::cout << "The total number of solutions is: " << solutions << std::endl;
    return 0;
}
获得输出:

1,2,5,100,
1,2,100,5,
The total number of solutions is: 2
相关文章: