KM算法模板题。

友情链接:百度百科KM算法:http://bk.baidu.com/view/739278.htm

注意事项:

1、在每次Dfs做匈牙利算法的时候都要将可更新值slack赋为无穷大

2、在扩大相等子图的时候注意要将不在交错树中的y节点的slack值减去更新值d

3、百度百科上给的程序复杂度为O(n^4),我的代码时间复杂度是O(n^3)

代码:

Program KM;//By_Thispoet
Const
	maxn=200;
Var
	i,j,k,m,n,toth,totm,d,ans				:Longint;
	slack,res,a,b							:Array[1..maxn]of Longint;
	vx,vy									:Array[1..maxn]of Boolean;
	pre,other,last,data						:Array[1..maxn*200]of Longint;
	ch										:Char;
	xh,yh,xm,ym								:Array[1..maxn]of Longint;
	ok										:Boolean;

Function Min(i,j:Longint):Longint;
begin
	if i<j then exit(i);exit(j);
end;


Function Dfs(i:Longint):Boolean;
var j,k:Longint;
begin
	j:=last[i];
	vx[i]:=true;
	while j<>0 do
		begin
			k:=other[j];
			if (not vy[k])and(data[j]=a[i]+b[k])then
				begin
					vy[k]:=true;
					if (res[k]=0)or(Dfs(res[k])) then
						begin
							res[k]:=i;
							exit(true);
						end;
				end else if (not vy[k])and(data[j]<a[i]+b[k]) then
					slack[k]:=Min(slack[k],a[i]+b[k]-data[j]);
			j:=pre[j];
		end;
	exit(false);
end;


BEGIN

	readln(n,m);
	while not((n=0)and(m=0)) do
		begin
			toth:=0;totm:=0;
			for i:=1 to n do
				begin
					for j:=1 to m do
						begin
							read(ch);
							if ch='m' then
								begin
									inc(totm);
									xm[totm]:=i;ym[totm]:=j;
								end else if ch='H' then
									begin
										inc(toth);
										xh[toth]:=i;yh[toth]:=j;
									end;
						end;
					readln;
				end;
		//init
			fillchar(last,sizeof(last),0);
			fillchar(b,sizeof(b),0);
			fillchar(a,sizeof(a),0);
			k:=0;
			for i:=1 to totm do
				begin
					for j:=1 to toth do
						begin
							inc(k);pre[k]:=last[i];last[i]:=k;other[k]:=j;
							data[k]:=300-(abs(xm[i]-xh[j])+abs(ym[i]-yh[j]));//need to be changed
							if data[k]>a[i] then a[i]:=data[k];
						end;
				end;
		//Build_Graph
			n:=totm;
			fillchar(res,sizeof(res),0);
			for j:=1 to n do
				begin
					repeat
						ok:=false;
						fillchar(vx,sizeof(vx),0);
						fillchar(vy,sizeof(vy),0);
						fillchar(slack,sizeof(slack),127);
						if Dfs(j) then ok:=true;
						if not ok then
							begin
								d:=maxlongint;
								for i:=1 to n do if not vy[i] then d:=Min(d,slack[i]);
								for i:=1 to n do
									begin
										if vx[i] then dec(a[i],d);
										if vy[i] then inc(b[i],d) else dec(slack[i],d);
									end;
							end;
					until ok;
				end;
		//KM
			ans:=0;
			for i:=1 to n do inc(ans,a[i]);
			for i:=1 to n do inc(ans,b[i]);
			ans:=300*n-ans;
			writeln(ans);
		//Getans
			readln(n,m);
		//prepare for the next test case
		end;

END.