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

sinxy 2008-05-22 05:10:44
算法原理
[img=http://p.blog.csdn.net/images/p_blog_csdn_net/sinxy/391124/o_11.bmp] [/img]
[img=http://p.blog.csdn.net/images/p_blog_csdn_net/sinxy/391124/o_22.bmp] [/img]
[img=http://p.blog.csdn.net/images/p_blog_csdn_net/sinxy/391124/o_33.bmp] [/img]

using System.Collections.Generic;
using System.Drawing;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ZMatrix m = new ZMatrix(4, 4);
m.Calculation();
int debug = 0;
}
}

class ZMatrix
{
private int[,] _data;
private List<Point> _result = new List<Point>();
private int _x;
private int _y;

public ZMatrix(int botNum, int PointNum)
{
_x = botNum;
_y = PointNum;
_data = new int[botNum, PointNum];

_data[0, 0] = 9;
_data[0, 1] = 4;
_data[0, 2] = 6;
_data[0, 3] = 8;

_data[1, 0] = 8;
_data[1, 1] = 5;
_data[1, 2] = 9;
_data[1, 3] = 10;

_data[2, 0] = 9;
_data[2, 1] = 7;
_data[2, 2] = 3;
_data[2, 3] = 5;

_data[3, 0] = 4;
_data[3, 1] = 8;
_data[3, 2] = 6;
_data[3, 3] = 9;
}

public void Calculation()
{
step1();
while (!step2())
step3();
}

/**/
/// <summary>
/// 畫出最少數目的垂直與水平的刪除線來包含所有的零至少一次。
/// </summary>
private void step3()
{
bool[,] isDelete = new bool[_x, _y];
for (int x = 0; x < _x; x++)
{
for (int y = 0; y < _y; y++)
{
if (_data[x, y] == 0 && !isDelete[x, y])
{
int xc = 0;
int yc = 0;

//lie
for (int nx = 0; nx < _x; nx++)
{
if (nx != x && _data[nx, y] == 0)
xc++;
}

//hang
for (int ny = 0; ny < _y; ny++)
{
if (ny != y && _data[x, ny] == 0)
yc++;
}

if (xc > yc)
{
for (int xx = 0; xx < _x; xx++)
isDelete[xx, y] = true;
}
else
{
for (int yy = 0; yy < _y; yy++)
isDelete[x, yy] = true;
}
}
}
}

//找出未被畫線的元素中之最小值 K
int k = 99999;
for (int x = 0; x < _x; x++)
{
for (int y = 0; y < _y; y++)
if (!isDelete[x, y])
if (_data[x, y] < k)
k = _data[x, y];
}

//將含有此些未被畫線的元素的各列所有元素減去K
for (int x = 0; x < _x; x++)
{
for (int y = 0; y < _y; y++)
{
if (!isDelete[x, y])
{
for (int y1 = 0; y1 < _y; y1++)
_data[x, y1] -= k;
break;
}
}
}

//若造成負值,則將該欄加上K (Step 4.2)。形成新矩陣後回到Step2
for (int x = 0; x < _x; x++)
{
for (int y = 0; y < _y; y++)
{
if (_data[x, y] < 0)
{
for (int x1 = 0; x1 < _x; x1++)
_data[x1, y] += k;
break;
}
}
}
}

/**/
/// <summary>
/// 檢驗各列,對碰上之第一個零,做記號,同列或同欄的其他零則畫X (由零較少的列先做,可不依順序)
///
/// 檢驗可否完成僅含零的完全指派,若不能,則false
/// </summary>
private bool step2()
{
_result.Clear();
bool[,] isDelete = new bool[_x, _y];

//零的数量由少到多
List<ZZeroNode> zeroNodes = new List<ZZeroNode>();
for (int x = 0; x < _x; x++)
{
int zeroNum = 0;
for (int y = 0; y < _y; y++)
if (_data[x, y] == 0)
zeroNum++;

if (zeroNum > 0)
zeroNodes.Add(new ZZeroNode(x, zeroNum));
}
zeroNodes.Sort(ZZeroNode.Cmp);

//从零较少的行开始
while (zeroNodes.Count > 0)
{
ZZeroNode node = zeroNodes[0];

if (node.ZeroNum <= 0)
zeroNodes.RemoveAt(0);
else
{
for (int y = 0; y < _y; y++)
{
if (_data[node.X, y] == 0 && !isDelete[node.X, y])
{
_result.Add(new Point(node.X, y));
zeroNodes.RemoveAt(0);

//删除与该零在同一列的其他零
for (int xxx = 0; xxx < _x; xxx++)
{
if (_data[xxx, y] == 0)
{
isDelete[xxx, y] = true;
for (int i = 0; i < zeroNodes.Count; i++)
if (zeroNodes[i].X == xxx)
zeroNodes[i].ZeroNum--;
}
}
break;
}
}
}
zeroNodes.Sort(ZZeroNode.Cmp);
}
return _result.Count == _x;
}


/// <summary>
/// 在各列中找最小值,將該列中各元素檢去此值,對各行重複一次。
/// </summary>
private void step1()
{
//列
for (int x = 0; x < _x; x++)
{
int minY = 99999;
//找到每列最小的值
for (int y = 0; y < _y; y++)
if (_data[x, y] < minY)
minY = _data[x, y];
//让该列减去最小的值
for (int y = 0; y < _y; y++)
_data[x, y] -= minY;
}
//行
for (int y = 0; y < _y; y++)
{
int minX = 99999;
//找到每列最小的值
for (int x = 0; x < _x; x++)
if (_data[x, y] < minX)
minX = _data[x, y];
//让该列减去最小的值
for (int x = 0; x < _x; x++)
_data[x, y] -= minX;
}
}
}

...全文
341 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
指派问题的匈牙利解法
sinxy 2008-05-22
  • 打赏
  • 举报
回复
   class ZZeroNode
{
public int X;
public int ZeroNum;

public ZZeroNode(int x, int zeroNum)
{
X = x;
ZeroNum = zeroNum;
}

public static int Cmp(ZZeroNode a, ZZeroNode b)
{
return a.ZeroNum.CompareTo(b.ZeroNum);
}
}
}

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧