搬运箱子的机器人

Robots moving boxes

这是一道我无法解决的考试问题,我需要解决它,因为我可以在下一次考试中再次面对它(它决定了你是 D 还是 A)。

问题:

"Two robots R1 and R2 carry boxes around a factory. R1 can carry 1 or 3 or 5 boxes at once, whereas R2 can carry 2 or 4 boxes at once. If there are 34 boxes, write a C# program that finds every movement combination of robot R1 and R2 carrying all the boxes. The movements occur in such a way that one robot may move after the other one (R1 gets the boxes, carries them in the required destination, and then R2 can go next). Also show which combination allows carrying all the boxes with minimal movement.

Possible combination: (R1=5,R2=4), (R1=3,R2=4), (R1=3,R2=2), (R1=3,R2=2), (R1=3,R2=2), (R1=1,R2=2)"

问题是我什至不知道从哪里开始。我写了一些可能的组合,希望我能得到从某个地方开始的线索。我尝试了一个程序,但它没有用(打印箱子的数量,直到从机器人那里拿走的箱子数量不为负:箱子-(r1 + r2)> = 0,这是一个特定的案例每一种可能的组合)

我从一位年长的学生那里找到了一个程序,他向我发送了以下 windows 表单代码:

            private void button1_Click(object sender, EventArgs e)
    {
        int Min = 34;
        string stMin = "";
        for(int i1=0;i1<=34;i1++)
            for (int i2 = 0; i2 <= 34; i2++)
                for (int i3 = 0; i3 <= 34; i3++)
                    for (int j1 = 0; j1 <= 34; j1++)
                        for (int j2 = 0; j2 <= 34; j2++)
                            for (int j3 = 0; j3 <= 34; j3++)
                            {
                                if (i1 * 3 + i2 * 4 + i3 * 5 + j1 * 1 + j2 * 2 + j3 * 3 == 34 && i1 > 0 && i2 > 0 && i3 > 0 && j1 > 0 && j2 > 0 && j3 > 0 && (i1 + i2 + i3 == j1 + j2 + j3))
                                {
                                    if(i1+i2+i3+j1+j2+j3<Min)
                                    {
                                        Min = i1 + i2 + i3 + j1 + j2 + j3;
                                        stMin = "R1 =>" + i1 + " x 3, " + i2 + " x 4 " + i3 + " x 5 " + "R2 =>" + j1
                                            + " x 1 " + j2 + " x 2 " + j3 + " x 3 "; 
                                    }
                                    string st = "R1 =>" + i1 + " x 3, " + i2 + " x 4 " + i3 + " x 5 " + "R2 =>" + j1
                                            + " x 1 " + j2 + " x 2 " + j3 + " x 3 ";
                                    listBox1.Items.Add(st);
                                }
                                listBox1.Items.Add("==========Min=========");
                                listBox1.Items.Add(stMin);
                            }
    }

我分析了3天,但我不知道这段代码是如何工作的。问他解释,但他说这不是他的代码,不记得他从哪里得到它,也不知道它是否有效。 也问过朋友同事都不知道怎么解决

如果有人能给我一个想法或一段代码来开始解决方案,我将不胜感激(编写完整的代码会很棒,不,我不会将其复制粘贴到我的考试中,我会看看最多理解代码的每一步)。
旁白:我是一名新手程序员。我的教授教我们一些基本的东西,比如阅读用户的输入、使用循环和创建 类。这么复杂的问题,我自学没能解决,所以请尽可能深入具体地解释你的解决方案。

提前致谢

好吧,既然你还好奇,那我们就来解决这个问题吧。

很经典,和往常一样,首先要非常清楚条件:

  • 可能的组合有:(R1=5,R2=4), (R1=3,R2=4), (R1=3,R2=2), (R1=3 ,R2=2), (R1=3,R2=2), (R1=1,R2=2)

  • 起始框数为34

这意味着当所有方框都消失时我们已经完成,并且如果我们有无效移动组合还剩 1 或 2 个箱子,因为我们的任何组合都无法移动这些箱子。

接下来让我们创建一个漂亮的数据结构来保存允许的组合,以便我们可以在循环中使用它;我们称这些为 'full moves':

Dictionary<string, int> fullMoves = new Dictionary<string, int>();

我们会将移动存储为字符串,还将存储每个组合移动的盒子总数..

接下来我们需要填充数据结构:

for (int i = 1; i <= 5; i += 2)
    for (int j = 2; j <= 4; j += 2)
        fullMoves.Add(i + "-" + j + "  ", i + j);

使用调试器测试它是否有效!

现在让我们进入正题:我们需要一个函数来完成真正的工作。

正如我在评论中所解释的,这是 递归 解决方案的典型问题。所有的选择都会创建一棵路径树(即完整移动的序列),而树(几乎)总是需要递归方法。它会一遍又一遍地调用自己,传递当前状态,直到完成,即达到 'halting condition'.

抽象目标是这样的:

  • 测试情况,如果是
    • 无效,丢弃
    • 完成,添加到解决方案列表
    • 未完成:开始工作(添加新选项)并对所有当前路径重复

这里有一段代码可以做到这一点。它传递当前路径列表和目前找到的正确解决方案。还有新的路径和盒子的数量仍然存在。

void moveBoxes(int count, string curMove, List<string> curMoveList, List<string> solutions)
{
    // test for halting conditions:
    // 1) count == 0: we're done with this solution
    if (count == 0)
    {
        solutions.Add(curMove);
        return;
    }
    // 2) less than three boxes: invalid solution:
    else if (count < 3)
    {
        curMoveList.Remove(curMove);
        return;
    }
    // keep moving..:
    foreach (string cm in curMoveList)
        foreach (string k in fullMoves.Keys)
        {
            int bc = count - fullMoves[k];
            moveBoxes( bc, curMove + k,  curMoveList, solutions );
        }
}

你可以看到它很短。这是递归解决方案中经常发现的一个特征。另一个是需要一些练习才能将你的头脑环绕起来。看,它以一种形式从嵌套的容器中收集TextBoxes

让我们来测试一下吧!这是一个测试平台,它运行许多框编号的代码,并向控制台写入每个起始编号获得的解决方案数量。最后一个起始数字 (34) 的解决方案也被写入 TextBox.

List<string> solutions = new List<string>();
List<string> curMoveList = new List<string>();
for (int ccc = 10; ccc <= 34; ccc++)
{
    solutions = new List<string>();
    curMoveList = new List<string>(); 

    int count = ccc;
    curMoveList.Add("");

    moveBoxes(count, "", curMoveList, solutions);

    Console.WriteLine(ccc + " boxes can be moved in " + solutions.Count + " ways.\r\n");
}
StringBuilder sb = new StringBuilder();
foreach (string s in solutions) sb.Append(s.Length / 5 + " moves:  " + s + "\r\n");
textBox1.Text = sb.ToString();

控制台输出如下:

10 boxes can be moved in 8 ways.
11 boxes can be moved in 6 ways.
12 boxes can be moved in 11 ways.
13 boxes can be moved in 18 ways.
14 boxes can be moved in 16 ways.
15 boxes can be moved in 36 ways.
16 boxes can be moved in 36 ways.
17 boxes can be moved in 58 ways.
18 boxes can be moved in 86 ways.
19 boxes can be moved in 98 ways.
20 boxes can be moved in 172 ways.
21 boxes can be moved in 201 ways.
22 boxes can be moved in 304 ways.
23 boxes can be moved in 432 ways.
24 boxes can be moved in 549 ways.
25 boxes can be moved in 856 ways.
26 boxes can be moved in 1088 ways.
27 boxes can be moved in 1587 ways.
28 boxes can be moved in 2220 ways.
29 boxes can be moved in 2966 ways.
30 boxes can be moved in 4364 ways.
31 boxes can be moved in 5798 ways.
32 boxes can be moved in 8284 ways.
33 boxes can be moved in 11529 ways.
34 boxes can be moved in 15760 ways.

Maje 一定要在 Stringbuilder 中收集输出;创建 15k 字符串很昂贵,将它们直接添加到 TextBox 需要 很长的 时间..

奖金*问题:

  • 为什么最后要除以5?-)
  • 为什么解决方案的数量不是总是增加?-)