最小点覆盖问题,采用匈牙利算法。

证明一下算法的正确性:

定义一段无法向左右扩展的连续泥地为行连通块,一段无法向上下扩展的连续泥地为列连通块。我们把行连通块对应X集合,列连通块对应Y集合,如果一个行连通块与一个列连通块有交点且为空地,则对应在二分图中有一条边。显然木板的集合对应二分图的一个匹配,任意两个木板不可能共同存在于一个行/列连通块中,所以最少木板数目=最大匹配数。证毕。

Program POJ2226;//by_Poetshy
Const 	
	maxn=50;
Var	
	i,j,k,m,n,sum,sum2,ans			:Longint;
	map								:Array[1..maxn,1..maxn]of Char;
	f								:Array[1..maxn,1..maxn,0..1]of Longint;
	pre,other,last,res				:Array[1..maxn*maxn]of Longint;
	state							:Array[1..maxn*maxn]of Boolean;
	
Function Dfs(i:Longint):Boolean;
var j,k:Longint;
begin
	j:=last[i];
	while j<>0 do
		begin
			k:=other[j];
			if not state[k] then
				begin
					state[k]:=true;
					if (res[k]=0)or(Dfs(res[k]))then
						begin
							res[k]:=i;
							exit(true);
						end;
				end;
			j:=pre[j];
		end;
	exit(false);
end;

BEGIN
	readln(m,n);
	for i:=1 to m do
		begin
			for j:=1 to n do
				read(map[i,j]);
			readln;
		end;
	fillchar(last,sizeof(last),0);
	sum:=0;sum2:=0;ans:=0;
	fillchar(f,sizeof(f),255);
	for i:=1 to m do
		for j:=1 to n do
			if (map[i,j]='*') then
				begin
					if f[i,j,0]=-1 then
						begin
							inc(sum);k:=i;
							while (k<=m)and(map[k,j]='*')do
								begin
									f[k,j,0]:=sum;
									inc(k);
								end;
						end;
					if f[i,j,1]=-1 then
						begin
							inc(sum2);k:=j;
							while (k<=n)and(map[i,k]='*')do
								begin
									f[i,k,1]:=sum2;
									inc(k);
								end;
						end;
				end;//Prepare the graph
	k:=0;
	for i:=1 to m do
		for j:=1 to n do
			begin
				if map[i,j]='*' then
					begin
						inc(k);
						pre[k]:=last[f[i,j,0]];last[f[i,j,0]]:=k;other[k]:=f[i,j,1];
					end;
			end;
	for i:=1 to sum do
		begin
			fillchar(state,sizeof(state),0);
			if Dfs(i) then inc(ans);
		end;
	writeln(ans);
END.