【问题标题】:Find best combination in MS Access VBA在 MS Access VBA 中找到最佳组合
【发布时间】:2014-11-28 09:36:54
【问题描述】:

我需要使用循环找到最佳组合来计算“NumerOfSheets”以从最大的数字中获得最小的可能数字。考虑到要分配的额外块。

我在运行代码之前的表格是这样的

 ID Oder Quantity Blocks NumberOfSheets
  1  A    350      2      
  2  B    200      1      
  3  C    100      1

一开始我使用的是代码(我没有额外的块):

Dim recIn As Recordset
Dim strSQL As String
strSQL = "SELECT * FROM tbl1;"
Set recIn = CurrentDb.OpenRecordset(strSQL)
While Not recIn.EOF
recIn.Edit
recIn!NumberOfSheets = Round((recIn!Quantity / recIn!Block), 1)
recIn.Update
recIn.MoveNext
Wend
recIn.Close`

成功了!但现在我的主表单“Forms!frmGlowny!FreeBlocks”中有一个新字段,我在其中保留要分配的块数(我可以在“块”列中分配的附加块)。该字段由另一个代码计数。现在重要的是,这是正整数(通常不超过 20)。我需要找到分配空闲块的最佳方法。什么是最好的方法? - “NumerOfSheets”中的最大数字应尽可能小。假设这个例子 Forms!frmGlowny!FreeBlocks = 1 (所以这是一个非常简单的例子)。所以让我们找到我应该在哪里分配我的 1 个空闲块(我需要手动完成,因为我没有代码:/)。

组合1

ID Oder Quantity Blocks NumberOfSheets
1  A    350      3       117  
2  B    200      1       200
3  C    100      1       100

组合2

ID Oder Quantity Blocks NumberOfSheets
1  A    350      2       175  
2  B    200      2       100
3  C    100      1       100

组合3

ID Oder Quantity Blocks NumberOfSheets
1  A    350      2       175  
2  B    200      1       200
3  C    100      2       50

最大中的最小可能数字在 2 号组合中(因为最大 = 175,所以它是所有最大组合中最小的),所以现在我知道我的 1 个空闲块应该添加到 B命令到“阻止”列。这是一个非常简单的例子,因为我只有 A;B;C oders 和 1 个块要分配。但是当我有例如命令时:A;B;C:D;E;F;G;H 和 14 个块来手动分配计数将是可怕的:/ 请大家帮帮我。我在互联网上找到的任何解决方案都是关于定义的行数(在我的情况下是订单) * 在运行代码之前,我总是知道订单;数量;块(在添加其他块之前)。

【问题讨论】:

  • 所以基本上这个问题的故事很长:给定一组数量为 Q 和块 B 的订单导致表 S = Round(Q/B),我如何分配 n 个空闲块 Bf使所有工作表的总和尽可能低?
  • 不,总和并不重要。只有“张数”中的最大数字很重要。代码应该找到如何分配空闲块以实现尽可能低的“大量”
  • 对不起。我不知道如何解决这个问题。我不认为这是一个编程问题。这更像是一个数学问题。也许你可以试试math.stackexchange.com
  • @venerik 好的,我知道没有办法实现一个简单的解决方案。但是请告诉我,是否有可能编写一个可以检查所有可能解决方案的代码?

标签: vba combinations combinatorics


【解决方案1】:

您可以做的是一次添加一个所有块。例如,如果要添加 14 个空闲块,首先添加 1。然后添加另一个。重复添加,直到处理完所有 14 个块。

我创建了一个little program 来演示。它是用 C# 编写的,因为我手头没有 Access。当您使用参数 1 启动程序时,它将为您提供正确的结果(将 1 个块添加到订单 B)。当您使用参数 2 启动它时,它会显示它首先向订单 B 添加 1 个块,然后向订单 A 添加 1 个块,订单如下所示:

 ID Oder Quantity Blocks NumberOfSheets
  1  A    350      3      117 
  2  B    200      2      100
  3  C    100      1      100

源代码:

public class Order
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Quantity { get; set; }
    public int Blocks { get; set; }
    public int NumberOfSheets
    {
        get
        {
            return (int)Math.Round((double)Quantity / Blocks);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var orders = new List<Order> {
            new Order {Id = 1, Name = "A", Quantity = 350, Blocks = 2},
            new Order {Id = 2, Name = "B", Quantity = 200, Blocks = 1},
            new Order {Id = 3, Name = "C", Quantity = 100, Blocks = 1}
        };

        Print(orders, "Initial set");

        // When you start the program you have to provide the number 
        // of free blocks as an argument.
        // Loop through all the blocks to add.
        for (int i = 0; i < Int32.Parse(args[0]); i++)
        {
            var lowestNumberOfSheets = 0;
            var orderToModify = 0;
            for (int j = 0; j < orders.Count; j++)
            {
                orders[j].Blocks++;
                // get number of sheets of the order 
                // with the highest number of sheets 
                var highestNumberOfSheets = orders.Max(o => o.NumberOfSheets);
                // when this number is lower than 
                // the lowestnumberofsheets remember order 
                orderToModify = lowestNumberOfSheets == 0 ? j : highestNumberOfSheets < lowestNumberOfSheets ? j : orderToModify;
                // and remember lowestnumberofsheets as well
                lowestNumberOfSheets = lowestNumberOfSheets == 0 ? highestNumberOfSheets : Math.Min(lowestNumberOfSheets, highestNumberOfSheets);
                Print(orders, "Orders after run " + (i + 1) + ", try " + (j + 1));
                orders[j].Blocks--;
            }
            orders[orderToModify].Blocks++;
            Console.WriteLine("Added block to order " + orders[orderToModify].Name);
            Print(orders, "Orders after run " + (i + 1));
        }

    }

    static void Print(List<Order> orders, string message = "")
    {
        if (!String.IsNullOrEmpty(message)) Console.WriteLine(message);

        Console.WriteLine("Id | Name | Quantity | Blocks | Sheets");
        foreach (var order in orders)
        {
            Console.WriteLine(" {0} | {1,4} | {2} | {3} | {4} "
                , order.Id
                , order.Name
                , order.Quantity.ToString().PadLeft(8)
                , order.Blocks.ToString().PadLeft(6)
                , order.NumberOfSheets.ToString().PadLeft(6));
        }
        Console.WriteLine();
    }
}

希望你能自己在VBA中实现这个算法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-17
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 2012-03-03
    • 1970-01-01
    • 2021-05-07
    • 1970-01-01
    相关资源
    最近更新 更多