【问题标题】:Generate a power multi-set from r elements that has size n从大小为 n 的 r 个元素生成一个幂多重集
【发布时间】:2012-07-18 05:43:40
【问题描述】:

我希望从 r 个大小为 n 的元素生成一个幂多集。

说函数是

public List<List<string>> PowerMultiSet (List<string> elems, int n )

示例 输入:{"d1","d2",d3"}, n=2 输出:{"d1","d1"}, {"d1","d2"},{"d1","d3"},{"d2","d2"}, {"d2","d3" },{"d3","d3"} 假设elems的大小为r,生成的元素个数为C(n+r-1,r-1)。

我想知道如何在没有冗余操作的情况下实现这一点(即理想情况下,数字操作应该是 = C(r+n-1,n-1))

非常感谢!

【问题讨论】:

  • 我不确定我是否理解正确:List&lt; List &lt; string &gt; &gt; 不是您想要的吗?你没有得到 n!/(n-k)!乘以 k 个条目?
  • 你的函数原型是C#的,你想要C#还是C++的解决方案?选一个!
  • C# 和 C++ 对我来说都可以,更喜欢 c#。是的,这是 List > 抱歉
  • 为什么是 n!/(n-k)!乘以 k 个条目?
  • 这可以是将 n 个相同的球分配到 r 个不同的盒子中,这些盒子允许空盒子,因此它有 C(r+n-1,n-1)

标签: c# c++ algorithm math combinatorics


【解决方案1】:

我认为下面的代码解决了这个问题:

void MultiSet(List<string> elems, int last, int n, ref List<string> set, ref List<List<string>> result)
{
    if (set.Count < n)
    {
        for (int index = last; index < elems.Count; index++)
        {
            set.Add(elems[index]);
            MultiSet(elems, index, n, ref set, ref result);
            set.RemoveAt(set.Count - 1);
        }
    }
    else
    {
        result.Add(new List<string>(set));
    }
}

List<List<string>> PowerMultiSet(List<string> elems, int n)
{
    var result = new List<List<string>>();
    var set = new List<string>();
    MultiSet(elems, 0, n, ref set, ref result);
    return result;
}

【讨论】:

  • 我在最后使用这个解决方案,因为它更快。
  • 您知道是否可以以某种方式安排迭代解决方案吗?理论上所有递归算法都可以表示为线性算法:)
【解决方案2】:

这可以通过递归方式来实现。使用空的start 调用下面的函数以开始递归。

public List<List<string>> PowerMultiSet (List<string> start, List<string> elems, int n )
{
    List<List<string>> output = new List<List<string>>();
    if (n > 0)
    {
        for (int i = 0; i < elems.Count; i++)
        {
            start.Add(elems[i]);
            List<List<string>> current = PowerMultiSet(start, elems.GetRange(i, elems.Count - i), n - 1);
            start.RemoveAt(start.Count - 1);
            output.AddRange(current);
        }
    }
    else
    {
        output.Add(new List<string>(start));
    }
    return output;
}

调用示例:

List<string> elems = new List<string> { "d1", "d2", "d3"};
List<string> start = new List<string>();
List<List<string>> x = PowerMultiSet(start, elems, 3);

【讨论】:

    【解决方案3】:

    这本质上是排列问题,除了每个排列的长度已经确定。为简化起见,假设我们正在打印集合并定义以下递归函数:

    public void PrintPowerMultiSets(List<string> elems, int index, List<string> ps, int num_left)
    

    其中 index 是我们想要添加到 powerset 的元素的索引,ps 是当前在这个分支中构建的 powerset,num_left 是我们仍然可以添加到 ps 的元素的数量。在对该函数的每次递归调用中,将 elems[index] 添加到 ps 并为 elems 中具有索引

    您只需为列表中的每个元素调用一次该函数即可。如果您完成它,我相信您会发现这与您手动枚举原始问题中的输出的方式相同。

    【讨论】:

      猜你喜欢
      • 2018-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-02
      • 2014-07-27
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      相关资源
      最近更新 更多