我试图学习回溯,为此我挑选了一个TopCoder问题 - 它叫做BridgeCrossing。我们有1-6人试图在晚上过桥,他们之间有一个手电筒。最多2个人可以一次过桥,当他们这样做时,至少有一个人必须有手电筒,否则他们什么都看不见......
答案是一个给出vector <int> times
的函数,其中times[i-1]
代表第i个人过桥所需的时间(当2个人过桥时,他们的时间是来自慢的人)。此外,当我们在桥的另一侧有手电筒时,仍然有一些人需要穿过桥 - 一个人必须带着手电筒返回才能引导他们通过。
这是我的解决方案(所有vector <int>
都出现在VI
)中:
int backtrack(VI times){
if (times.empty()) return 0;
if (times.size() == 1) return times[0];
if (times.size() == 2) return max(times[0], times[1]);
VI results;
for (int i = 0; i < times.size(); i++){
for (int j = 0; j < i; j++){
VI people_left1;
for (int k = 0; k < times.size(); k++){
if (k != i && k != j){
people_left1.push_back(times[k]);
}
}
people_left1.push_back(min(times[i], times[j]));
results.push_back(backtrack(people_left1)+
max(times[i], times[j]) + min(times[i], times[j]));
}
for (int j= i + 1; j < times.size(); j++){
VI people_left;
for (int k = 0; k < times.size(); k++){
if (k != i && k != j){
people_left.push_back(times[k]);
}
}
people_left.push_back(min(times[i], times[j]));
results.push_back(backtrack(people_left)+
max(times[i], times[j]) + min(times[i], times[j]));
}
}
int res = INT_MAX;
for (int i = 0; i < results.size(); i++){
if (results[i] < res){
res = results[i];
}
}
return res;
}
理论上它应该运作良好 - 我选择所有可能的指数i,j,引导一个人(有更长的时间)通过,与一个人一起返回并递归左边的人。不幸的是它不起作用 - 输入{1,2,5,10}
它应该返回17,但我的函数输出19。
我已经盯着这段代码很长一段时间了,我仍然看不到任何错误。一个人可以藏在哪里?另外,调试这种递归函数的技术是什么,因为我现在已经有很长时间没有这样做了。
答案 0 :(得分:1)
不是真正的答案,但通过这样做,您的代码可以更具可读性:
for (int j = 0; j < times.size(); j++){
if (j != i) {
.. all that code inside both loops
}
}
也许这会让您更容易找到问题。
您可以通过根据递归级别打印缩进信息来调试递归代码。要执行此操作,您必须添加一个在每个级别传递的变量。当你调低一个关卡时增加它。
method(int level, ...) {
if (recursing needed) {
print(spaces(level * 3) + "recursing");
method(level + 1);
}
}
答案 1 :(得分:1)
问题在于,您不会认为已经留在另一侧的人将来可以使用手电筒返回。在示例情况下,人员编号2在一段时间后返回。基本上并不总是来自i,j对的人会带着手电筒返回。