# 貪婪 ## 工作排程1 :::success 最多有幾個工作可以執行 ::: ### 題目說明 有$n$個工作可以執行,給定每個工作的開始時間與結束時間,時間從$0$開始,開始與結束時間都是整數,只有一台機器可以執行,每次只能執行一個工作,且工作一旦開始就必須做完,機器執行中不能跳到另一個工作,可以一結束就馬上接著執行另一個工作,機器更換工作很快,可以不考慮切換所需時間,請計算執行完後最多有幾個工作被完成? ### 輸入說明 每次輸入數字$n$,$n$表示需要執行的工作個數,輸入$n$小於$100$,之後有$n$行分別是每一行兩個整數$s$與$e$,$s$表示工作的開始時間與$e$表示工作的結束時間,且$s$永遠小於$e$。 ### 輸出說明 輸出一個數字,表示結束時最多有幾個工作被完成。 ### 輸入輸出範例 輸入範例 5 1 10 2 4 3 6 2 5 4 9 輸出範例 2 ```cpp= #include <iostream> #include <algorithm> // for sort() using namespace std; //定義一個工作的資料型別 /* struct JOB{ int start; //工作開始時間 int end; //工作結束時間 }; */ typedef struct _job{ int start; int end; }JOB; const int MAXN = 100+5; //最大的工作數量 JOB jobs[MAXN]; //儲存所有輸入工作的陣列 bool cmp(JOB p, JOB q){ if(p.end==q.end) return(p.start<q.start); else return (p.end<q.end); } //顯示陣列內容;驗證輸入資料 void showArray(int n) { for(int i=0;i<n;++i){ cout<<jobs[i].start<<" "<<jobs[i].end<<"\n"; } } int main() { //工作輸入: n筆工作 int n; //不斷輸入n筆工作直到使用者按下ctrl+Z while(cin>>n){ //將n筆工作讀入並存入陣列中 for(int i=0;i<n;++i){ cin>>jobs[i].start>>jobs[i].end; } sort(jobs, jobs+n, cmp); //showArray(n); //模擬工作運算 int res=0; //紀錄已經完成的工作數量 int curTime = -1; //代表目前工作時間 for(int i=0; i<n; i++){ //目前機器可以執行第i個工作 if(curTime<=jobs[i].start){ //設定工作時間至第i個工作結束的時間 curTime=jobs[i].end; res++; //可執行工作+1 } }cout<<res<<"\n"; } return 0; } ``` ![](https://i.imgur.com/hPum75T.png) ## 工作排程2 :::success 最多有幾台機器一起運作 ::: ### 題目說明 有$n$個工作可以執行,給定每個工作的開始時間與結束時間,工作時間可能重疊,時間從$0$開始,開始與結束時間都是整數,有$n$台機器可以執行,每台機器同時間只可以執行一個工作,工作可以到每台機器去執行,且工作開始做就需要做完,機器執行中不能跳到另一個工作,可以一結束就馬上接著執行另一個工作,機器更換工作很快,可以不考慮切換所需時間,執行完後最少需要幾台機器才能完成所有工作? ### 輸入說明 每次輸入數字$n$,$n$表示需要執行的工作個數,輸入$n$小於$100$,之後有$n$行分別是每一行兩個整數$s$與$e$,$s$表示工作的開始時間與$e$表示工作的結束時間,且$s$永遠小於$e$。 ### 輸出說明 輸出一個數字,表示需要幾台機器才能在指定的時間執行完所有工作。 ### 輸入輸出範例 輸入範例 5 1 10 2 4 3 6 2 5 4 9 輸出範例 4 ```cpp= #include <iostream> #include <algorithm> // for sort() using namespace std; typedef struct _job{ int start; int end; }JOB; const int MAXN = 100+5; //最大的工作數量 JOB jobs[MAXN]; //儲存所有輸入工作的陣列 int endTimes[MAXN]; //紀錄所有運行中的工作結束時間 //自訂排序 //比較工作(結構)開始時間小的排前面 //若開始時間相同結束時間小的排前面 int cmp(JOB p, JOB q){ if(p.start==q.start) return(p.end<q.end); else return (p.start<q.start); } //顯示陣列內容;驗證輸入資料 void showArray(int n) { for(int i=0;i<n;++i){ cout<<jobs[i].start<<" "<<jobs[i].end<<"\n"; } } int main() { //工作輸入: n筆工作 int n; //不斷輸入n筆工作直到使用者按下ctrl+Z while(cin>>n){ //將n筆工作讀入並存入陣列中 for(int i=0; i<n; i++){ cin>>jobs[i].start>>jobs[i].end; } sort(jobs, jobs+n, cmp); showArray(n); //Process: int res=1; //第一台機器啟動 endTimes[0]=jobs[0].end; //從第2個工作開始到最後一個工作判斷 //下一個工作的開始時間是否大於等於已經在運行的 //工作結束時間 bool found; //是否有找到沒在用的機器 for(int i=1; i<n; i++){ found = false; for(int j=0; j<res; j++){ if(jobs[i].start>=endTimes[j]){ //判斷第i個工作開始時間是否大於等於第j個工作的結束時間 found = true; //找到空閒的機器 endTimes[j] = jobs[i].end; //重設工作結束時間 break; } } if(!found){ //沒有空閒的機器 endTimes[res]=jobs[i].end; res++; } } cout<<res<<"\n"; } return 0; } ``` ![](https://i.imgur.com/lEZh2KJ.png) ## 工作排程3 :::success 最小平均等待時間 ::: ### 題目說明 有$n$個工作從開始就進入到機器,給予$n$個工作的執行需要的時間,只有一台機器可以執行,每次只能執行一個工作,且工作開始做就需要做完,機器執行中不能跳到另一個工作,請計算完成所有工作所需要的最小平均等待時間? ### 輸入說明 每次輸入數字$n$,$n$表示需要執行的工作個數,輸入$n$小於$100$,之後有$n$行分別是每一行一個整數$x$,$x$表示工作執行完成所需時間。 ### 輸出說明 輸出一個浮點數,表示執行所有工作的最小平均等待時間。 ### 輸入輸出範例 輸入範例 5 10 4 6 5 9 輸出範例 10.4 ```cpp= #include <iostream> #include <algorithm> // for sort() using namespace std; const int MAXN = 100+5;//最大工作數量 int workTimes[MAXN]; //儲存輸入的每個完成所需的時間 int main() { int n; while(cin>>n){ //資料輸入 for(int i=0; i<n; i++){ cin>>workTimes[i]; } //資料處理 sort(workTimes, workTimes+n); //預設由小到大排序 int curTime=0; //紀錄目前執行時間 int waitTime=0; //紀錄等待執行時間 //從第i筆到n-1筆 for(int i=0; i<n-1; i++){ //第i個工作開始時間 //curTime += workTimes[i]; curTime = curTime + workTimes[i]; //累計等待時間 //waitTime += curTime; waitTime = waitTime + curTime; } cout<<(double)waitTime/n<<"\n"; } return 0; } ``` ![](https://i.imgur.com/N1MjOGd.png) ## 工作排程4 :::success 有截止期限的最大利潤 ::: ### 題目說明 假設剛開始有$n$個工作進入到機器,給予$n$個工作的截止時間與獲得的利潤,只有一台機器可以執行,每個工作都需花費一個單位時間執行,請計算在截止時間前如何安排工作執行,可以獲得最大利潤? ### 輸入說明 每次輸入數字$n$,$n$表示需要執行的工作個數,輸入$n$小於$100$,之後有$n$ 行分別是每一行兩個整數 $x$與$income,x$表示工作的截止時間,而$income$表示執行該工作所獲得的利潤。 ### 輸出說明 輸出一個整數,表示在截止時間前完成工作的最大利潤總和。 ### 輸入輸出範例 輸入範例 5 2 10 3 4 1 5 2 7 3 8 輸出範例 25 ```cpp= #include <iostream> #include <algorithm> // for sort() using namespace std; const int MAXN = 100+5;//最大工作數量 //自訂每個工作的型態 typedef struct _job{ int profit; //工作結束時間 int end; //工作利潤 }JOB; JOB jobs[MAXN]; //記錄所有工作的陣列 JOB works[MAXN]; //紀錄已經選用的工作 //自訂排序比較 //工作利潤大的排前面 //若利潤相同,工作結束時間小的排前面 int cmp1(JOB p, JOB q) { if(p.profit==q.profit) return(p.end<q.end); else return (p.profit>q.profit); } //自訂排序比較 //結束時間小的排前面 int cmp2(JOB p, JOB q) { return (p.end<q.end); } int main() { int n; while(cin>>n){ for(int i=0; i<n; i++){ cin>>jobs[i].end>>jobs[i].profit; } //將工作利潤高的排前面 sort(jobs, jobs+n, cmp1); //第1筆先選用 works[0] = jobs[0]; int counter=1; //紀錄已選用的筆數 //從第2個工作到第n個工作比對使否可以放置在已選用的陣列位置 for(int i=1; i<n; i++){ bool found = false; //紀錄是否找到已選用的空間 int idx; //在已選用陣列的索引位置 //依序比對所有已選的工作結束時間 for(idx=0; idx<counter; idx++ ){ //目前的工作結束時間(第i個)是否小於等於已選的工作結束時間 if(jobs[i].end<=works[idx].end){ found = true; //找到 break; } } //找出應該放在的地方(考慮結束時間相同的狀態) //有找到 //確保idx不會產生索引錯誤 // 目前工作結束時間與下一個工作結束時間相同 while(found && (idx<(counter-1)) && works[idx+1].end==works[idx].end){ idx++; //工作週期加1 } //如果沒找到小於等於已選的工作結束時間 if(!found){ //直接將第i個工作加入已選的工作陣列中 works[counter] = jobs[i]; //已選的工作數量加1 counter++; //已選的工作陣列以工作結束時間由小到大排序 sort(works, works+counter, cmp2); }else if((idx+1) < jobs[i].end){ works[counter] = jobs[i]; //已選的工作數量加1 counter++; //已選的工作陣列以工作結束時間由小到大排序 sort(works, works+counter, cmp2); } } int res=0; for(int i=0; i<counter; i++){ res = res + works[i].profit; } cout<<res<<"\n"; } return 0; } ``` ![](https://i.imgur.com/tprUx4b.png)