回溯法求解:最佳排程問題
阿新 • • 發佈:2020-12-21
一、問題描述:
假設有 n 個任務由 k 個可並行工作的機器來完成,完成任務 i 需要的時間為。試著設計一個演算法,找出完成這個 n 個任務的最佳排程,使得完成全部任務的時間最早。
資料輸入:
第一行有 2 個正整數 n 和 k 。第 2 行的 n 個正整數是完成 n 個任務需要的時間。
測試樣例:
——輸入:
7 3
2 14 4 16 6 5 3
——輸出:
17
二、演算法分析:
其實回溯法的本質就是將所有的執行路線都安排一遍;而且安排的時候使得在邏輯上構成一個樹狀結構;再通過相應的特徵量或者函式來修剪這顆“樹”;可以快速排除一些明顯得不到最優解的分配路徑;使得更加快速的得到最優解。
因為有 n 個任務需要分配,而且每一個任務的分配都可以選擇 k 個機器中的任意一個;故所有可行解在邏輯上構成的“樹”狀結構有 n 層,每一個結點有 k 個分支;因此我們需要記錄下每一個支路累計的時間,在每次分配完時,選出其中一個最小的累計時間作為區域性最優解;再使用遞迴遍歷所有的情形,最終得到整體最優解,即完成全部任務的最短時間。
三、程式碼實現:
import java.util.Scanner; public class demo{ public static void main(String[] args) { Scanner s = new Scanner(System.in); int n = s.nextInt();//表示任務的數量 int k = s.nextInt();//表示機器的數量 int[] time = new int[n+1];//表示各個工作對應的時間長短 for(int i = 1;i<=n;i++) time[i] = s.nextInt(); s.close();//接收完畢 int[] time_length = new int[k+1];//用於記錄K條支路的當前累計的時間 backTrack(1, time_length, time, n, k); System.out.println("最短的時間為:"+bestanswer); } public static int bestanswer = 10000; /* * dep表示深度 */ public static void backTrack(int dep,int[]time_length,int[]time,int n,int k) { if(dep==n+1) {//表示已經分配完了 int tmp = comp(k,time_length); if(tmp<bestanswer) {//記錄最佳值 bestanswer = tmp; } return; } for(int i = 1;i<=k;i++) { time_length[i]+=time[dep]; if(time_length[i]<bestanswer)//剪枝的作用 backTrack(dep+1, time_length, time, n, k); time_length[i]-=time[dep];//恢復數值 } } //找到當前分配方案下所有支路中的最長時間 public static int comp(int k,int[] len) { int tmp=0; for(int i = 1;i<=k;i++) { if(len[i]>tmp) tmp=len[i]; } return tmp; } }
四、執行結果:
Ending... ...