1. 程式人生 > 其它 >回溯法求解:最佳排程問題

回溯法求解:最佳排程問題

技術標籤:# 演算法回溯法Java

一、問題描述:

假設有 n 個任務由 k 個可並行工作的機器來完成,完成任務 i 需要的時間為t_{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... ...