过桥问题

问题

小明一家过一座桥,过桥时是黑夜,所以必须有灯。现在小明过桥要1秒,小明的弟弟要3秒,小明的爸爸要6秒,小明的妈妈要8秒,小明的爷爷要12秒。每 次此桥最多可过两人,而过桥的速度依过桥最慢者而定,而且灯在点燃后30秒就会 熄灭。问:小明一家如何过桥?

分析

为了最短时间过桥,尽量每次用时最短的返回。

首先,第一快与第二快先过。
中间是第一快依次去接剩余中最快的。
倒数第二组是第一慢与第二慢一起过桥。
最后第二快的去接第一快的。

主要证明,为何这样是最省时间的。

每次过桥分为两部分:两人过桥一人返程,两部分时间之和是这次的总共耗时。

每次一定是这种过桥时间最短是局部最优解,所有局部最优解之和是全局最优解。

所以第一次是第一快和第二快先过桥,第一快返回。

情况一
第一快走两趟,去接第三快和第四快。
情况二
第三快和第四快一起走,第三快返回再与第一快过桥。
这两种情况取用时最少的那种情况。

依次类推,至到全部过桥。

  • 详细版:保留中间过桥信息
#include 
#include 
#include 
#include 
#include 
using namespace std;

void PrintCross(int a,int b){
    cout << "Cross:" << a << "," << b << endl;
}

void PrintBack(int a){
    cout << "Back:" << a << endl;
}

void PrintVec(vector const& vec){
    cout << "vec:";
    copy(vec.begin(),vec.end(),ostream_iterator(cout," "));
    cout << endl;
}
int CrossBridge(vector vec){
    if(vec.empty()) return 0;
    sort(vec.begin(),vec.end());
    PrintVec(vec);
    deque uncross(vec.begin(),vec.end());

    int min1st = uncross.front();
    uncross.pop_front();
    // 只有一个人过桥的情况
    if(uncross.empty()) return min1st;
    int min2nd = uncross.front();
    uncross.pop_front();
    int spend(0);

    // 第一次过桥
    PrintCross(min1st,min2nd);
    spend = min2nd;
    while(!uncross.empty()){
        // 最快返回
        PrintBack(min1st);
        spend += min1st;

        // 最慢的优先过桥
        int max1st = uncross.back();
        uncross.pop_back();
        if(uncross.empty()){ // 如果只有一个最后一次过桥
            PrintCross(min1st,max1st);
            spend += max1st;
        }else{ // 每次最慢与次慢过桥,次快返回
            int max2st = uncross.back();
            uncross.pop_back();
            PrintCross(max1st,max2st);
            PrintBack(min2nd);
            PrintCross(min1st,min2nd);
            spend += max1st + min2nd*2;     
        }
    }

    return spend;
}
int main(){
    cout << CrossBridge({1,3,6,8,12}) << endl;
    cout << CrossBridge({1,3,6,8}) << endl;
    cout << CrossBridge({1,3,6}) << endl;
    cout << CrossBridge({1,3}) << endl;
    cout << CrossBridge({1}) << endl;
    cout << CrossBridge({}) << endl;
}
  • 精简版:删除中间过桥信息
#include 
#include 
#include 
#include 
#include 
using namespace std;

int CrossBridge(vector vec){
    if(vec.empty()) return 0;
    sort(vec.begin(),vec.end());
    deque uncross(vec.begin(),vec.end());

    int min1st = uncross.front();
    uncross.pop_front();
    // 只有一个人过桥的情况
    if(uncross.empty()) return min1st;
    int min2nd = uncross.front();
    uncross.pop_front();
    int spend(0);

    // 第一次过桥
    spend = min2nd;
    while(!uncross.empty()){
        // 最快返回
        spend += min1st;

        // 最慢的优先过桥
        int max1st = uncross.back();
        uncross.pop_back();
        if(uncross.empty()){ // 如果只有一个最后一次过桥
            spend += max1st;
        }else{ // 每次最慢与次慢过桥,次快返回
            int max2st = uncross.back();
            uncross.pop_back();
            spend += max1st + min2nd*2;     
        }
    }

    return spend;
}

int main(){
    cout << CrossBridge({1,3,6,8,12}) << endl;
    cout << CrossBridge({1,3,6,8}) << endl;
    cout << CrossBridge({1,3,6}) << endl;
    cout << CrossBridge({1,3}) << endl;
    cout << CrossBridge({1}) << endl;
    cout << CrossBridge({}) << endl;
}

待加分析说明,如有问题请留言

你可能感兴趣的:(过桥问题)