POJ2195 Going Home——二分图最大带权匹配的KM算法——pku2195

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.

你可能感兴趣的:(home)