最佳调度问题(回溯算法)

概述

掌握调度问题的处理方法,实现最佳调度问题的回溯解决。

解题思路

一个深度为NM叉树。
基本思路:

  • 搜索从开始结点(根结点)出发,以DFS搜索整个解空间。
  • 每搜索完一条路径则记录下besttimebestx[]序列
  • 开始结点就成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处向纵深方向移至一个新结点,并成为一个新的活结点,也成为当前扩展结点。
  • 如果在当前的扩展结点处不能再向纵深方向扩展,则当前扩展结点就成为死结点。
  • 此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点;直至找到一个解或全部解。

程序代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package demo4;

import java.util.Random;

/**
* 最佳调度问题
*/
public class BestSchedule {

/**
* 任务数
*/
int N;
/**
* 机器数
*/
int M;
/**
* 最优值=最优时间
*/
int best;
/**
* 每个任务所需的时间序列
*/
int[] t;
/**
* 每台机器所需时间序列
*/
int[] len;
/**
* 当前路径=机器编号
* x[i]=j:i任务,j机子编号
*/
int[] x;
/**
* 最优调度:其中bestx[i]=m表示把第i项任务分配给第m台机器
*/
int[] bestx;

public static void main(String[] args) {
BestSchedule bs = new BestSchedule();
bs.showTest();
}

void showTest() {
N = 10; // 任务数
M = 7; // 机器数目
Random r = new Random();
// 每个任务的时间
t = new int[N];
//随机分配每个任务所需要的时间
for (int i = 0; i < N; i++) {
t[i] = r.nextInt(5 * N);
}
// 记录每台机器所需要的时间
len = new int[M];
best = Integer.MAX_VALUE;
// N个任务分配第几台机子
bestx = new int[N];
x = new int[N];

Long startTime = System.nanoTime();
backtrack(0);
Long endTime = System.nanoTime();
System.out.println("总耗时: " + (endTime - startTime) + " ns");

System.out.print("最优时间:");
System.out.println(best);
System.out.print("每个任务所需要时间:");
for (int i = 0; i < N; i++){
System.out.print(t[i] + " ");
}
System.out.println();
System.out.print("最优调度:");
for (int i = 0; i < N; i++){
System.out.print(bestx[i] + " ");
}
}

/**
* 回溯搜索
* @param dep 任务编号
*/
void backtrack(int dep) {
//打印最优解数据,打印i个任务由那个机子执行效率高
if (dep == N) {
//时间
int tmp = comp();
//比最优解时间都小
if (tmp < best) {
//最优时间
best = tmp;
//遍历N个任务
for (int i = 0; i < N; i++) {
//第i任务分配给x[i]个机器
bestx[i] = x[i];
}
}
return;
}

//遍历机器
//
for (int i = 0; i < M; i++) {
//第i台机子执行任务所需时间+dep任务所需要的时间
len[i] += t[dep];
//机子下标从1开始
//当前任务dep由i机子执行
x[dep] = i + 1;
//i台机子执行完当前dep任务的时间比最优解小,执行下一个任务
//下一个任务继续循环遍历机子
//会在最优解时间内执行完任务,那么此任务符合条件
//问题:导致每台机子执行,都有可能是最优解,每个任务都被所有机子执行
if (len[i] < best) {
backtrack(dep + 1);
}
//当前机子i执行任务dep,不比最优解小,减去当前dep任务执行的时间
//继续下一个机子i+1执行dep任务
len[i] -= t[dep];
}
}

/**
* 计算完成任务的时间
* @return 机器执行任务时间
*/
int comp() {
//机器完成任务时间
int tmp = 0;
//遍历机器
for (int i = 0; i < M; i++) {
//当前机器执行任务时间>之前机器执行任务时间
if (len[i] > tmp) {
tmp = len[i];
}
}
return tmp;
}

}

结果:

1
2
3
4
总耗时: 6291008 ns
最优时间:45
每个任务所需要时间:11 7 45 44 14 15 2 20 41 39
最优调度:1 1 2 3 1 4 1 4 5 6

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×