題目
爲慶祝強漢文武盛世暨廢除和親七百週年,武后決定拜孫武和王翳對春夏秋冬四官:細君、昭君、探春、文成四人座軍事訓練。
孫武和王翳分別負責四官的站軍姿和踢正步科目;根據軍訓要求,只有在學會站軍姿之後才能進行踢正步訓練,但由於四官天資差別,學習時間如下表:
問題
問:應該如何安排四官的學習時間,才能夠使得所有人都學會上述兩項技能的時間最短?
算法分析
首先我們來看,如果按原始的順序,即春夏秋冬四個人的順序,就是什麼安排也不做,最終會耗時多久:
可以看到,如果什麼計劃和安排也不做,所有人都學會這兩項技能就會消耗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;