匈牙利算法的C#实现版本

算法的原理:

   

範例:

有四位教授被分派開設四門課程,如何指派使所需的總準備時間為最小。已知個人對各課程之準備時間如下表所示:

  

課程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 為最佳解。

算法的实现代码

  1using System.Collections.Generic;
  2using System.Drawing;
  3
  4namespace ConsoleApplication1
  5{
  6    class Program
  7    {
  8        static void Main(string[] args)
  9        {
 10            ZMatrix m = new ZMatrix(44);
 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[00= 9;
 33            _data[01= 4;
 34            _data[02= 6;
 35            _data[03= 8;
 36
 37            _data[10= 8;
 38            _data[11= 5;
 39            _data[12= 9;
 40            _data[13= 10;
 41
 42            _data[20= 9;
 43            _data[21= 7;
 44            _data[22= 3;
 45            _data[23= 5;
 46
 47            _data[30= 4;
 48            _data[31= 8;
 49            _data[32= 6;
 50            _data[33= 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