运筹学指派问题的匈牙利法实验报告

  • 格式:doc
  • 大小:204.98 KB
  • 文档页数:15

下载文档原格式

  / 15
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

运筹学

专业:

班级:

学号:

2012年6月20日

目录

一、题目。

二、算法思想。

三、算法步骤。

四、算法源程序。

五、算例和结果。

六、结论与总结。

一、题目:匈牙利法求解指派问题。

二、算法思想。

匈牙利解法的指派问题最优解的以下性质:

设指派问题的系数矩阵为C=()c ij n n⨯,若将C的一行(或列)各元素分别减去一个常数k(如该行或列的最小元素),则得到一个新的矩阵C’=()'c ij n n⨯。那么,以C’位系数矩阵的指派问题和以C位系数矩阵的原指派问题有相同最优解。

由于系数矩阵的这种变化不影响约束方程组,只是使目标函数值减少了常

数k,所以,最优解并不改变。必须指出,虽然不比要求指派问题系数矩阵中无

负元素,但在匈牙利法求解指派问题时,为了从以变换后的系数矩阵中判别能否

得到最优指派方案,要求此时的系数矩阵中无负元素。因为只有这样,才能从总

费用为零这一特征判定此时的指派方案为最优指派方案。

三、算法步骤。

(1)变换系数矩阵,使各行和各列皆出现零元素。

各行及各列分别减去本行及本列最小元素,这样可保证每行及每列中都有

零元素,同时,也避免了出现负元素。

(2)做能覆盖所有零元素的最少数目的直线集合。

因此,若直线数等于n,则以可得出最优解。否则,转第(3)步。

对于系数矩阵非负的指派问题来说,总费用为零的指派方案一定是最优指派方案。在第(1)步的基础上,若能找到n个不同行、不同列的零元素,则对应的指派方案总费用为零,从而是最优的。当同一行(或列)上有几个零元素时,如选择其一,则其与的零元素就不能再被选择,从而成为多余的。因此,重要的是零元素能恰当地分布在不同行和不同列上,而并在与它们的多少。但第(1)步并不能保证这一要求。若覆盖所有零元素的最少数目的直线集合中的直线数目是n,则表明能做到这一点。

此时,可以从零元素的最少的行或列开始圈“0”,每圈一个“0”,同时把位于同行合同列的其他零元素划去(标记为),如此逐步进行,最终可得n个位于不同行、不同列的零元素,他们就对应了最优解;若覆盖所有零元素的最少数目的直线集合中的元素个数少于n,则表明无法实现这一点。需要对零元素的分布做适当调整,这就是第(3)步。

(3)变换系数矩阵,是未被直线覆盖的元素中出现零元素。回到第(2)步。

在未被直线覆盖的元素中总有一个最小元素。对未被直线覆盖的元素所在的行(或列)中各元素都减去这一最小元素,这样,在未被直线覆盖的元素中势必会出现零元素,但同时却又是以被直线覆盖的元素中出现负元素。为了消除负元素,只要对它们所在的列(或行)中个元素都加上这一最小元素(可以看作减去这一最小元素的相反数)即可。

四、算法源程序。

#include

#include

#define m 5

int input(int M[m][m])

{

int i,j;

for(i=0;i

{ cout<<"请输入系数矩阵第"<

for(j=0;j

cin>>M[i][j];

}

cout<<"系数矩阵为:"<

for(i=0;i

{ for(j=0;j

cout<

cout<

}

return M[m][m];

}

int convert(int M[m][m])

{ int x[m],y[m];

int i,j;

for(i=0;i

{ x[i]=M[i][0];

for(j=1;j

{ if(M[i][j]

x[i]=M[i][j];

}

}

for(i=0;i

for(j=0;j

M[i][j]-=x[i];

for(j=0;j

{ y[j]=M[0][j];

for(i=0;i

{ if(M[i][j]

y[j]=M[i][j];

}

}

for(i=0;i

for(j=0;j

M[i][j]-=y[j];

cout<<"对系数矩阵各行各列进行变换得:"<

for(i=0;i

{ for(j=0;j

cout<

cout<

}

return M[m][m];

}

int exchange(int M[m][m])

{ int i,j,n;

cout<<"进行行变换输入0,进行列变换输入其他任意键:"<

cin>>n;

if(n==0)

cout<<"分别输入要变换的行及该行未覆盖元素中最小元素:"<

else

cout<<"分别输入要变换的列及该列的最小元素:"<

int a,b;

cin>>a>>b;

for(j=0;j

if(n==0)

M[a-1][j]-=b;

else

M[j][a-1]-=b;

cout<<"变换后的矩阵:"<

for(i=0;i

{ for(j=0;j

cout<

cout<

}