目标
我正在尝试使用BFS制作Rubik的立方体解算器。我知道它可能会因为所有可以置换的方式而变慢。如果有人想知道的话,这不适合学校。
可能很容易解决的问题
每当我将扰乱的Rubik立方体的另一个状态放入queue<array>
时,它只是一个浅层副本,所以一旦添加了Rubik立方体的其他状态,队列中的先前状态实际上会改变并匹配与较新的州。换句话说,我如何确保queue<array>
内的所有元素保持不变?
尝试修复此问题
https://stackoverflow.com/a/129395/984680
我基本上使用这个代码来创建一个新的立方体副本,当它从队列中出来时,然后我再创建另一个新副本,然后再将它放入队列(处于不同的状态)。下面的代码显示了在将新副本插入队列之前如何制作新副本。
//make deep copy of ccube (char array)
char[][][] newcube = DeepClone(ccube);
buffer.Enqueue(new State(newcube, calg + face + " ")); //even though newcube gets put into array, it ends up changed after ccube changes
这是从队列前面拉出阵列时的深度复制。
ccube = DeepClone(buffer.Peek().cube);
即使我克隆了这么多次(有些东西告诉我我不需要制作那么多副本),我添加的新状态仍然与旧状态相同。我知道这一点,因为队列中只有2个不同的元素,即使我每次都以各种方式使立方体的所有面都转动。
提前感谢能够提供帮助的任何人。
答案 0 :(得分:0)
问题是数组在C#中是可变的,即当您在修改现有数组的位置更改元素而不是生成新数组时。
字符串在C#中是不可变的,因为您已经将该多维数据集表示为char[][][]
,所以您可以利用这一事实。有界正交3D空间可以双向映射(1:1)到有界1D空间,即您的char[][][]
可以映射到字符串(只要立方体的维度在立方体的生命周期内不会改变),所以将其与字符串的不变性相结合,您可以轻松地深度克隆您的立方体。
public class Cube
{
public int Width { get; private set; }
public int Height { get; private set; }
public int Depth { get; private set; }
private string _data;
public Cube(int width, int height, int depth)
{
Width = width;
Height = height;
Depth = depth;
_data = "".PadRight(Width*Height*Depth);
}
public char Get(int x, int y, int z)
{
return _data[(Width*Height*z) + (Width*y) + x];
}
public void Set(int x, int y, int z, char c)
{
var sb = new StringBuilder(_data);
sb[(Width*Height*z) + (Width*y) + x] = c;
_data = sb.ToString();
}
public Cube Clone()
{
return new Cube(Width, Height, Depth) { _data = this._data };
}
}
每当你打电话给aCube.Clone()
时,你会得到一个与前一个完全无关的新立方体,所以你可以将它排入缓冲区等等。