【问题标题】:Get set of random numbers from input List having fixed sum using C#使用 C# 从具有固定总和的输入列表中获取一组随机数
【发布时间】:2017-03-12 11:34:41
【问题描述】:

我正在寻找一种 C# 算法,它会从输入 List 中给我一组随机整数,这样获得的随机整数之和为 N。

例如: 如果列表是 {1,2,3,4,5,6...100} 并且 N 是 20,那么算法应该返回一组随机数,例如 {5,6,9} 或 {9,11}或 {1,2,3,4,10} 等。

请注意,结果集中的整数计数不需要固定。此外,输入列表可以有重复的整数。性能是我的首要任务之一,因为输入列表可能很大(大约 1000 个整数),我需要在单个 Web 请求中随机化大约 2-3 次。如果列表存在性能问题,我可以灵活地不坚持将列表作为数据类型。

我尝试了以下非常初级且性能低下的方法:

  1. 使用 Random 类从输入列表中获取随机索引
  2. 从输入列表中获取整数,该列表位于 #1 中获得的索引处。让我们将此整数称为 X。
  3. 总和 = 总和 + X。
  4. 从输入列表中删除 X,使其不会被下一步选中。
  5. 如果 Sum 小于所需的总 N,则将 X 添加到 outputList 并返回到 #1。
  6. 如果 Sum 大于所需的总 N,请重新初始化所有内容并重新启动该过程。
  7. 如果 Sum 等于所需的总 N,则返回 outputList

    while(!reachedTotal)
    {
        //Initialize everything
        inputList.AddRange(originalInputList);
        outputList = new List<int>();
        while (!reachedTotal)
        {
            random = r.Next(inputList.Count);
            sum += inputList.ElementAt(random);
            if(sum<N)
            {
    
                outputList.Add(inputList.ElementAt(random));
                inputList.RemoveAt(random);
            }
            else if(sum>N)
                break;
            else
                reachedTotal = true;
        }
    }
    

【问题讨论】:

  • 为什么只描述你使用的代码。也发一下...
  • 这个列表是任意的还是你知道它的一些特征(例如由连续的数字组成)?如果它是任意的,那么问题是子集和的变体,它是 NP 完全的。
  • 是否保证存在解决方案?
  • @NicoSchertler - 该列表是任意的。
  • @Benj 解决方案无法保证。但我可以接受总 N 的 10% 差异。

标签: c# algorithm list random sum


【解决方案1】:

这是一种随机方法,可为您提供 N 的 10% 范围内的解决方案 - 假设存在一个

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace StackOverflowSnippets
{
    class Program
    {
        static void Main(string[] args)
        {
            // ----------------------------------------------------------------------------------
            // The code you are interested in starts below this line
            const Int32 N = 100;
            Int32 nLowerBound = (90 * N) / 100; Int32 nUpperBound = (110 * N) / 100;

            Random rnd = new Random();
            Int32 runningSum = 0;
            Int32 nextIndex = 0;

            List<Int32> inputList = GenerateRandomList( /* entries = */ 1000);
            List<Int32> o = new List<Int32>();

            while (runningSum < nLowerBound)
            {
                nextIndex = rnd.Next(inputList.Count); if (nUpperBound < (runningSum + inputList[nextIndex])) continue;

                runningSum += inputList[nextIndex];
                o.Add(inputList[nextIndex]);
                inputList.RemoveAt(nextIndex);
            }
            // The code you are interested in ends above this line
            // ----------------------------------------------------------------------------------

            StringBuilder b = new StringBuilder();

            for(Int32 i = 0; i < o.Count;i++)
            {
                if (b.Length != 0) b.Append(",");
                b.Append(o[i].ToString());
            }

            Console.WriteLine("Exact N    : " + N);
            Console.WriteLine("Upper Bound: " + nUpperBound);
            Console.WriteLine("Lower Bound: " + nLowerBound);
            Console.WriteLine();

            Console.WriteLine("sum(" + b.ToString() + ")=" + GetSum(o).ToString());
            Console.ReadLine();
        }

        // -------------------------------------------------------------------
        #region Helper methods
        private static object GetSum(List<int> o)
        {
            Int32 sum = 0;

            foreach (Int32 i in o) sum += i;

            return sum;
        }
        private static List<Int32> GenerateRandomList(Int32 entries)
        {
            List<Int32> l = new List<Int32>();

            for(Int32 i = 1; i < entries; i++)
            {
                l.Add(i);
            }

            return l;
        }
        #endregion
    }
}

编辑

  1. 忘记从输入列表中删除元素,因此无法选择两次
  2. 修复了“删除元素”插入

【讨论】:

  • 谢谢本杰。我对您的答案做了一个更改 - 首先将 int 添加到 outputList,然后从 inputList 中删除 :)
猜你喜欢
  • 2019-04-16
  • 2015-07-30
  • 2021-12-20
  • 2014-07-25
  • 1970-01-01
  • 2020-06-25
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多