这是一个我无法解决的考试问题,我需要解决它,因为我可以在下次考试时再次面对它(它决定你是否得到D或A)。
问题:
"两个机器人R1和R2在工厂周围携带盒子。 R1可以同时携带1或3或5个盒子,而R2可以同时携带2个或4个盒子。如果有34个盒子,写一个C#程序,找到机器人R1和R2的每个移动组合,携带所有盒子。移动的方式是一个机器人可以在另一个机器人之后移动(R1获取盒子,将它们带到所需的目的地,然后R2可以进入下一个)。还显示哪种组合允许以最小的移动携带所有盒子。
可能的组合:(R1 = 5,R2 = 4),(R1 = 3,R2 = 4),(R1 = 3,R2 = 2),(R1 = 3,R2 = 2),(R1 = 3) ,R2 = 2),(R1 = 1,R2 = 2)"
问题在于我甚至不知道从哪里开始。我写了一些可能的组合,希望我可以从某处开始获得线索。我尝试了一个程序,但它没有工作(打印盒子的数量,直到从机器人中取出的盒子数量不是负数:box-(r1 + r2)> = 0,这是一个特定的每种可能的组合中的情况)
我找到了一位来自年龄较大的学生的程序,该程序向我发送了以下窗体代码:
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天但我不知道这段代码是如何工作的。问他解释,但他说这不是他的代码,不记得他得到它的地方,也不知道它是否有效。 我也问了朋友和同事,但没有人知道如何解决它。
如果有人可以给我一个想法或一段代码来开始解决方案,我将不胜感激(编写完整的代码会很棒,而且我不会将它复制粘贴到我的考试中,我会看最多了解代码的每一步)。
旁边信息:我是新手程序员。我的教授给我们提供了基本的东西,比如从用户那里读取输入,使用循环和创建类。我的自学并没有达到如此复杂的问题,所以请尽可能深入和具体地解释你的解决方案。
提前谢谢
答案 0 :(得分:2)
好吧,既然你仍然好奇我们就解决了这个问题。
这是一个经典的,与往常一样,第一件事是要非常清楚条件:
这些可能的组合:(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个方框,我们也会处于无效组合移动中,因为这些我们的任何组合都无法移动。
让我们接下来创建一个很好的数据结构来保存允许的组合,这样我们就可以在循环中使用它;让我们称那些'完全移动':
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);
使用调试器测试它,看看它是否有效!
现在让我们开始做生意:我们需要一个功能来完成真正的工作。
正如我在评论中所解释的,这是递归解决方案的典型问题。所有的选择都会创建一条路径树(即完整移动的序列),树(几乎)总是要求递归的方法。它将一遍又一遍地召唤自己,将目前的状况传递出去,直到完成,即已达到“暂停状态”。
抽象的目标是:
这是一段代码就是这样做的。它传递了当前路径列表和到目前为止找到的正确解决方案。此外,新路径和方框数仍然存在。
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 );
}
}
你可以看到它很短。这是递归解决方案中常见的一个功能。另一个是需要一些练习来包裹你的头。查看here for a simpler example,它从表单中的嵌套容器中收集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个盒子可以8种方式移动。
11个盒子可以移动6个 方式。
12个箱子可以11种方式移动.1箱子可以移动 18种方式.14个盒子可以16种方式移动.15个盒子可以 以36种方式移动.16个箱子可以36种方式移动.17箱 可以58种方式移动。
可以86种方式移动18个盒子 箱子可以98种方式移动.21个箱子可以移动172个 方式.21箱可以201个方式移动.21个箱子可以移动 304方式.23箱可以432个方向移动.24箱可以 以549种方式移动.25箱可以856种方式移动。
26 箱子可以1088个方式移动。左边有27个箱子可以移动 方式。
28箱可以2220个方式移动.29箱可以 以2966种方式移动.21箱可以4364种方式移动 箱子可以5798种方式移动.21箱子可以在8284移动 方式。
33箱可以11529种方式移动.34箱可以 以15760种方式移动。
Maje肯定会收集Stringbuilder
的输出;创建15k
字符串非常昂贵,并将它们直接添加到TextBox
,需要真正的长时间。
加分*问题: