问题
给你一个n*n的图,上面有m个需要清楚的障碍,每次可以消除一行或者一列上的障碍物。问你最少用多少次,可以消除图上的所有障碍。
分析
关键是构图,我们将原图抽象成一个二分图:左边是x,右边是y,如果(x,y)上有障碍物,那么就连一条边。我们的任务是消除障碍物,也就是说,用最少的点覆盖图中所有的边!
也就是求二分图的最小点集覆盖!
我们用到一个强大的定理:二分图最小点集覆盖数=最大匹配数,网上有好多证明。
这里大体说一种思路,如果最大匹配的边涉及到的点无法将所有边覆盖,那么当前匹配一定不是最大匹配!
code
program liukee;
var
a:array[1..1200,0..1200] of longint;
match:array[1..1200] of longint;
v:array[1..1200] of boolean;
n,i,k,ans:longint;
procedure init;
var
x,y:longint;
begin
readln(n,k);
for i:=1 to k do
begin
readln(x,y);
inc(a[x,0]);
inc(a[y+n,0]);
a[x,a[x,0]]:=y+n;
a[y+n,a[y+n,0]]:=x;
end;
end;
function dfs(s:longint):boolean;
var
i:longint;
begin
for i:=1 to a[s,0] do
if v[a[s,i]]=false then
begin
v[a[s,i]]:=true;
if (match[a[s,i]]=0)or(dfs(match[a[s,i]])) then
begin
match[a[s,i]]:=s;
exit(true);
end;
end;
exit(false);
end;
begin
init;
for i:=1 to n+n do
begin
fillchar(v,sizeof(v),0);
if dfs(i) then inc(ans);
end;
writeln(ans>>1);
end.
反思
要想到二分图,抽象。掌握定理!