算法的原理:
範例:
有四位教授被分派開設四門課程,如何指派使所需的總準備時間為最小。已知個人對各課程之準備時間如下表所示:
|
|
課程1
|
課程2
|
課程3
|
課程4
|
|
教授A
|
2
|
10
|
9
|
7
|
|
教授B
|
15
|
4
|
14
|
8
|
|
教授C
|
13
|
14
|
16
|
11
|
|
教授D
|
4
|
15
|
13
|
9
|
解法:
Step 1. 在各列中找最小值,將該列中各元素檢去此值,對各行重複一次。
|
0
|
8
|
7
|
5
|
本列各減2
|
|
11
|
0
|
10
|
4
|
本列各減4
|
|
2
|
3
|
5
|
0
|
本列各減11
|
|
0
|
11
|
9
|
5
|
本列各減4
|
|
0
|
8
|
2
|
5
|
|
11
|
0
|
5
|
4
|
|
2
|
3
|
0
|
0
|
|
0
|
11
|
4
|
5
|
|
本欄各減0
|
本欄各減0
|
本欄各減5
|
本欄各減0
|
Step 2. 檢驗各列,對碰上之第一個零,做記號,同列或同欄的其他零則畫X (由零較少的列先做,可不依順序)
|
0
|
8
|
2
|
5
|
|
11
|
0
|
5
|
4
|
|
2
|
3
|
0
|
0
|
|
0
|
11
|
4
|
5
|
Step 3. 檢驗可否完成僅含零的完全指派,若不能,則畫出最少數目的垂直與水平的刪除線來包含所有的零至少一次。
|
0
|
8
|
2
|
5
|
|
11
|
0
|
5
|
4
|
|
2
|
3
|
0
|
0
|
|
0
|
11
|
4
|
5
|
Step 4. 找出未被畫線的元素中之最小值 K,將含有此些未被畫線的元素的各列所有元素減去K (Step 4.1),若造成負值,則將該欄加上K (Step 4.2)。形成新矩陣後回到Step 2.
Step 4.1
|
-2
|
6
|
0
|
3
|
|
11
|
0
|
5
|
4
|
|
2
|
3
|
0
|
0
|
|
-2
|
9
|
2
|
3
|
Step 4.2
|
0
|
6
|
0
|
3
|
|
13
|
0
|
5
|
4
|
|
4
|
3
|
0
|
0
|
|
0
|
9
|
2
|
3
|
形成新矩陣
Step 2.
|
0
|
6
|
0
|
3
|
|
13
|
0
|
5
|
4
|
|
4
|
3
|
0
|
0
|
|
0
|
9
|
2
|
3
|
由上表知,指派順序為 (2,2), (4,1), (1,3), (3,4),可得到完全指派。
|
|
課程1
|
課程2
|
課程3
|
課程4
|
|
教授A
|
|
|
9
|
|
|
教授B
|
|
4
|
|
|
|
教授C
|
|
|
|
11
|
|
教授D
|
4
|
|
|
|
總準備時間為 9+4+11+4 = 28 為最佳解。
算法的实现代码
1
using System.Collections.Generic;
2
using System.Drawing;
3
4
namespace ConsoleApplication1
5

{
6
class Program
7
{
8
static void Main(string[] args)
9
{
10
ZMatrix m = new ZMatrix(4, 4);
11
12
m.Calculation();
13
14
15
int debug = 0;
16
}
17
}
18
19
class ZMatrix
20
{
21
private int[,] _data;
22
private List<Point> _result = new List<Point>();
23
private int _x;
24
private int _y;
25
26
public ZMatrix(int botNum, int PointNum)
27
{
28
_x = botNum;
29
_y = PointNum;
30
_data = new int[botNum, PointNum];
31
32
_data[0, 0] = 9;
33
_data[0, 1] = 4;
34
_data[0, 2] = 6;
35
_data[0, 3] = 8;
36
37
_data[1, 0] = 8;
38
_data[1, 1] = 5;
39
_data[1, 2] = 9;
40
_data[1, 3] = 10;
41
42
_data[2, 0] = 9;
43
_data[2, 1] = 7;
44
_data[2, 2] = 3;
45
_data[2, 3] = 5;
46
47
_data[3, 0] = 4;
48
_data[3, 1] = 8;
49
_data[3, 2] = 6;
50
_data[3, 3] = 9;
51
}
52
53
public void Calculation()
54
{
55
step1();
56
while (!step2())
57
{
58
step3();
59
}
60
}
61
62
/**//// <summary>
63
/// 畫出最少數目的垂直與水平的刪除線來包含所有的零至少一次。
64
/// </summary>
65
private void step3()
66
{
67
bool[,] isDelete = new bool[_x, _y];
68
for (int x = 0; x < _x; x++)
69
{
70
for (int y = 0; y < _y; y++)
71
{
72
if (_data[x, y] == 0 && !isDelete[x, y])
73
{
74
int xc = 0;
75
int yc = 0;
76
77
//lie
78
for (int nx = 0; nx < _x; nx++)
79
{
80
if (nx != x && _data[nx, y] == 0)
81
{
82
xc++;
83
}
84
}
85
86
//hang
87
for (int ny = 0; ny < _y; ny++)
88
{
89
if (ny != y && _data[x, ny] == 0)
90
{
91
yc++;
92
}
93
}
94
95
if (xc > yc)
96
{
97
for (int xx = 0; xx < _x; xx++)
98