先用floyed判断两点是否联通。
把一个点v拆成vx,vy。如果i能到达j,那么连边(ix,jy)。
求最大点独立集,即最大匹配。
剩下的点都两两不联通了,于是答案就等于总点数-最大匹配。
二分图相关结论:
最小点覆盖(用最少的点覆盖所有的边)=最大匹配
最小边覆盖(用最少的边覆盖所有的点)=最大匹配+总点数-2*最大匹配=总点数-最大匹配
因为除了匹配边覆盖的点,剩下的点每个需要一条边覆盖。
最大点独立集(最大的两两不联通的点集)=总点数-最小点覆盖=总点数-最大匹配
因为删掉那些在最小点覆盖里的点以后,就已经删掉所有边了
type
edge=^edgenode;
edgenode=record
t:longint;
next:edge;
end;
var
n,m,u,v,i,j,k,ans:longint;
con:array[1..210]of edge;
link:array[1..210]of longint;
f:array[1..110,1..110]of boolean;
visit:array[1..210]of boolean;
procedure ins(x,y:longint);
var
p:edge;
begin
new(P);
p^.t:=y;
p^.next:=con[x];
con[x]:=p;
end;
function pipei(x:longint):boolean;
var
p:edge;
begin
pipei:=false;
p:=con[x];
visit[x]:=true;
while p<>nil do
begin
if visit[p^.t]=false then
begin
visit[p^.t]:=true;
if (link[p^.t]=-1)or(pipei(link[p^.t])=true) then
begin
link[p^.t]:=x;
exit(true);
end;
end;
p:=p^.next;
end;
end;
begin
readln(n,m);
for i:=1 to m do
begin
readln(u,v);
f[u,v]:=true;
end;
for k:=1 to n do
for i:=1 to n do
for j:=1 to n do
f[i,j]:=f[i,j]or(f[i,k] and f[k,j]);
for i:=1 to n do
for j:=1 to n do
if f[i,j]=true then begin ins(i,j+n); end;
for i:=1 to n do
link[i+n]:=-1;
for i:=1 to n do
begin
fillchar(visit,sizeof(visit),false);
if pipei(i)=true then inc(ans);
end;
writeln(n-ans);
end.