正在载入在线练习界面,本页内容可直接阅读…

AK CSP › NOIP 普及 2010 第一轮真题 › 第 36 题

NOIP 普及 2010 第一轮 第 36 题:过桥问题的最短时间搜索:第 5 空

完善程序 · 搜索与图遍历(DFS/BFS) · 答案 pos[i] = LEFT

题目

完善程序:
(过河问题) 在一个月黑风高的夜晚,有一群人在河的右岸,想通过唯一的一根独木桥走到河的左岸。在这伸手不见五指的黑夜里,过桥时必须借助灯光来照明,很不幸的是,他们只有一盏灯。另外,独木桥上最多承受两个人同时经过,否则将会坍塌。每个人单独过桥都需要一定的时间,不同的人需要的时间可能不同。两个人一起过桥时,由于只有一盏灯,所以需要的时间是较慢的那个人单独过桥时所花的时间。现输入 $n(2\leq n<100$ 和这 $n$ 个人单独过桥时需要的时间,请计算总共最少需要多少时间,他们才能全部到达河的左岸。

例如,有 $3$ 个人甲、乙、丙,他们单独过桥的时间分别为 $1,2,4$,则总共最少需要的时间为 $7$。具体方法是:甲、乙一起过桥到河的左岸,甲单独回到河的右岸将灯带回,然后甲、丙再一起过桥到河的左岸,总时间为 $2+1+4=7$。

#include <iostream>
using namespace std;

const int SIZE = 100;
const int INFINITY = 10000;
const bool LEFT = true;
const bool RIGHT = false;
const bool LEFT_TO_RIGHT = true;
const bool RIGHT_TO_LEFT = false;

int n, hour[SIZE];
bool pos[SIZE];

int max(int a, int b)
{
    if (a > b)
        return a;
    else
        return b;
}

int go(bool stage)
{
    int i, j, num, tmp, ans;
    if (stage == RIGHT_TO_LEFT) {
        num = 0;
        ans = 0;
        for (i = 1; i <= n; i++)
            if (pos[i] == RIGHT) {
                num++;
                if (hour[i] > ans)
                    ans = hour[i];
            }
        if ([    ①    ])
            return ans;
        ans = INFINITY;
        for (i = 1; i <= n - 1; i++)
            if (pos[i] == RIGHT)
                for (j = i + 1; j <= n; j++)
                    if (pos[j] == RIGHT) {
                        pos[i] = LEFT;
                        pos[j] = LEFT;
                        tmp = max(hour[i], hour[j]) +[     ②    ];
                        if (tmp < ans)
                           ans = tmp;
                        pos[i] = RIGHT;
                        pos[j] = RIGHT;
                    }
        return ans;
    }
    if (stage == LEFT_TO_RIGHT) {
        ans = INFINITY;
        for (i = 1; i <= n; i++)
            if ([    ③    ]) {
                pos[i] = RIGHT;
                tmp =[    ④    ];
                if (tmp < ans)
                    ans = tmp;
            [        ⑤    ];
            }
        return ans;
    }
    return 0;
}

int main()
{
    int i;

    cin>>n;
    for (i = 1; i <=n; i++) {
        cin>>hour[i];
        pos[i] = RIGHT;
    }
    cout<<go(RIGHT_TO_LEFT)<<endl;
    return 0;
}

本小题

⑤处应填( )

答案

pos[i] = LEFT

题解

考点定位

本题(过河第⑤空)考「状态回退」,对应大纲 4.2.3 递归(难度【2】)。

解题过程

⑤处枚举完一个返回者后恢复状态(把 i 送回左岸),供下一轮枚举:

``cpp pos[i] = LEFT; ``

等一下——③处枚举的是 pos[i]==LEFT 的人返回(进入时把他置 RIGHT),⑤处恢复为 LEFT ✓。

答案:pos[i] = LEFT。

易错提醒

① 枚举-恢复(回溯)成对出现:改状态 → 递归 → 恢复状态;② R→L 阶段的枚举也有同样的「置 LEFT 再恢复 RIGHT」配对(见 ② 前后),双向都要回溯。

真题版权归 CCF 所有,本站仅用于非商业教学用途。页面加载后可直接在线作答,作答记录保存在本浏览器或账号中。 京ICP备2026056990号-1 京公网安备11010502062986号