算法面试题 -- 迷离傍地走

题目

为庆祝强汉文武盛世暨废除和亲七百周年,武后决定拜孙武和王翳对春夏秋冬四官:细君、昭君、探春、文成四人座军事训练。
孙武和王翳分别负责四官的站军姿踢正步科目;根据军训要求,只有在学会站军姿之后才能进行踢正步训练,但由于四官天资差别,学习时间如下表:
时间表

问题

问:应该如何安排四官的学习时间,才能够使得所有人都学会上述两项技能的时间最短?

算法分析

首先我们来看,如果按原始的顺序,即春夏秋冬四个人的顺序,就是什么安排也不做,最终会耗时多久:
最坏的情况
可以看到,如果什么计划和安排也不做,所有人都学会这两项技能就会消耗32个小时,但是能不能做到更少呢?很明显,先前我们是按照春夏秋冬四个人的原始顺序来安排的,如何我们把四官的训练顺序做一下合理的调整呢?这样会不会降低时间成本呢,好,我们接着往下分析。
上表中可以看到,四官在两项技能上的最短时间是昭君踢正步,为1小时,这个时间在所有踢正步的四个人里是最短的,但是踢正步是必须要在站军姿学会后才能学习的,所以我们把这一事件放在最后执行;再来看,其中的次短时间是探春的站军姿,为2小时,这个时间很明显也是四个人中(站军姿)最短的,因为站军姿就是位于踢正步之前,所以把这个时间放在第一位执行;然后再看,再次短时间是探春的踢正步,为3小时,所以把它放在倒数第二位执行,这样依次下去,学习安排表就显而易见了。
最好的情况

思路总结:因为只有两种学科(站军姿和踢正步),并且站军姿在踢正步之前,所以将所有站军姿的按照时间由少到多正排序,而将踢正步的按照时间由少到多逆排序。

Code

void AllAlgorithms::getShortestTime(const int *a, const int *b, int *c, int size){
    int size2 = size * 2;
    //整理数据
    HLItem *item = new HLItem[size2];
    for (int i = 0; i < size2; i ++) {
        item[i].t = a[i];
        item[i].idx = i;
        item[i].first = true;
        item[i + size].t = b[i];
        item[size + i].idx = i;
        item[size + i].first = false;
    }

    sort(item, item + size2);

    bool *bArrage = new bool[size];//第i号已经安排
    for (int i = 0; i < size; i ++) {
        bArrage[i] = false;
    }

    int from = 0;
    int to = size - 1;
    for (int i = 0; i < size2; i ++) {
        if(bArrage[item[i].idx])//item[i].idx已经确定
            continue;
        bArrage[item[i].idx] = true;
        if (item[i].first) {
            c[from] = item[i].idx;
            from ++;
        }
        else{
            c[to] = item[i].idx;
            to --;

        }
        if(to - from < 0)//提前退出
            break;
    }
    delete [] item;
    delete [] bArrage;
}


typedef struct tagItem{
    int t;
    int idx;
    bool first;
    bool operator < (struct tagItem& item) const{
        return t < item.t;
    }

}HLItem;
  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值