我的回溯代码中的错误 - Bridge Crossing

时间:2015-01-16 19:14:44

标签: c++ algorithm backtracking

我试图学习回溯,为此我挑选了一个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。

我已经盯着这段代码很长一段时间了,我仍然看不到任何错误。一个人可以藏在哪里?另外,调试这种递归函数的技术是什么,因为我现在已经有很长时间没有这样做了。

2 个答案:

答案 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对的人会带着手电筒返回。