号码分布

时间:2019-01-11 20:11:08

标签: c# algorithm

我在分配数字以完全适合给定容器方面遇到问题。我的电话号码是:

int[] number = {50, 40, 30, 30, 25, 25};

我想找到一个最接近100的最佳组合,并且当没有更多可用选项时,再启动另一个100容器。简单的解决方案(如从max到min的排序和添加)将不起作用,因为:

int[] firstContainer = { 50, 40 };         //10 unused
int[] secontContainer = { 30, 30, 25 };    //15 unused
int[] thirdContainer = { 25 };             //75 unused

我正在寻找的结果是:

int[] firstContainer = { 50, 25, 25 };     //0 unused
int[] secontContainer = { 40, 30, 30 };    //0 unused

有什么好心的人愿意帮助我解决问题吗?

3 个答案:

答案 0 :(得分:1)

这是一个解决方案-可以对其进行优化和改进,但是现在您有了一个起点。起点是创建初始数组的所有组合,然后获取总和

static void Main(string[] args)
{
    int[] number = { 50, 40, 30, 30, 25, 25 };

    foreach (var kvp in Exercise(number, 100))
    {
        Console.WriteLine("Solution " + kvp.Key);
        foreach (var sol in kvp.Value)
        {
            Console.Write(sol + " ");
        }
        Console.WriteLine();
    }
}

private static Dictionary<int, List<int>> Exercise(int[] number, int sum)
{
    Dictionary<int, List<int>> results = new Dictionary<int, List<int>>();
    int counter = 0;

    var numberOfCombinations = Math.Pow(2, number.Count());
    for (int i = 0; i < numberOfCombinations; i++)
    {
        //convert an int to binary and pad it with 0, so I will get an array which is the same size of the input[] array. ie for example 00000, then 00001, .... 11111 
        var temp = Convert.ToString(i, 2).PadLeft(number.Count(), '0').ToArray();
        List<int> positions = new List<int>();
        int total = 0;
        for (int k = 0; k < temp.Length; k++)
        {
            if (temp[k] == '1')
            {
                total += number[k];
                positions.Add(number[k]);
            }
        }

        if (total == sum)
        {
            results.Add(counter, positions);
            counter++;
        }
    }

    return results;
}

答案 1 :(得分:0)

我的解决方案基于生成随机且可行的答案,最后我们可以找到最佳答案:

static void Main(string[] args)
    {

        int[] number = { 50, 40, 30, 30, 25, 25 };
        int bound = 100;
        var numbers = new List<dynamic>();
        Random rnd = new Random();
        var ans_collection = new List<List<List<int>>>();
        //number of random answers , best answer depends on i so you can't be sure this algorithm always finds optimal answer choose i big enough...
        for (int i = 0; i < 100; i++)
        {
            for (int j = 0; j < number.Length; j++)
            {
                numbers.Add(new { num = number[j], seen = false });
            }
            var ans = new List<List<int>>();
            var container = new List<int>();
            var distSum = 0;
            //while loop generates a distribution
            while (numbers.Where(x => !x.seen).Count() > 0)
            {
                var chosen = numbers.OrderBy(x => rnd.NextDouble()).Where(x => !x.seen && distSum + x.num <= bound).FirstOrDefault();
                if (numbers.Where(x => !x.seen && distSum + x.num <= bound).Count() > 0)
                {
                    container.Add(chosen.num);
                    distSum += chosen.num;
                    numbers.Add(new { num = chosen.num, seen = true });
                    numbers.Remove(chosen);
                    if (numbers.Where(x => !x.seen && distSum + x.num <= bound).Count() == 0)
                    {
                        ans.Add(new List<int>(container));
                        container = new List<int>();
                        distSum = 0;
                    }
                }
                else
                {
                    ans.Add(new List<int>(container));
                    container = new List<int>();
                    distSum = 0;
                }
            }
            ans_collection.Add(new List<List<int>>(ans));
        }


        //find best answer based on sum of *unused* amounts
        var min = ans_collection.Min(ans => ans.Sum(dis => (bound - dis.Sum())));
        var best = ans_collection.Where(ans => ans.Sum(dis => (bound - dis.Sum())) == min).FirstOrDefault();

        best.ForEach(x => Console.WriteLine(string.Join(",", x.Select(Y => Y.ToString()))));
    }

答案 2 :(得分:0)

您要解决的问题是计算机科学中的一个众所周知的问题,称为knapsack problem(更确切地说是 0-1背包问题)。关于这个特定问题有大量文献,知道这个名称可能会帮助您在网络上找到各种解决方案和启发式方法。

只知道它是NP-Hard,这意味着没有 个多项式时间算法as of yet可以解决一般情况(尽管一般情况是可解决的,效率不高)。