poj2594

时间:2023-12-29 08:20:02

特殊的最小路径覆盖
回顾一下经典的最小路径覆盖问题是每个点都恰好被一条路径覆盖
我们把有向无环图的点拆成i,i',对于原图中边i--->j,连边i-->j'
做最大匹配,答案是原图点数-最大匹配
但这道题每个点可以被覆盖多次,所以我们考虑先dfs出每个点可以访问的点
然后拆点,如果i可以到达j,那么连边i-->j',答案是原图点数-最大匹配
为什么呢,感性的想一下,在最小路径覆盖的基础上既然每个点可以被多次经过
那么干脆我们把两个可达的点认为是直接飞过去就好了~ ~

 type node=record
point,next:longint;
end; var edge:array[..] of node;
a:array[..,..] of boolean;
p,cx,cy:array[..] of longint;
v:array[..] of boolean;
x,y,n,m,i,j,ans,len:longint; procedure add(x,y:longint);
begin
inc(len);
edge[len].point:=y;
edge[len].next:=p[x];
p[x]:=len;
end; function find(x:longint):longint;
var i,y:longint;
begin
i:=p[x];
while i<>- do
begin
y:=edge[i].point;
if not v[y] then
begin
v[y]:=true;
if (cy[y]=-) or (find(cy[y])=) then
begin
cx[x]:=y;
cy[y]:=x;
exit();
end;
end;
i:=edge[i].next;
end;
exit();
end; procedure dfs(x:longint);
var i,y:longint;
begin
i:=p[x];
v[x]:=true;
while i<>- do
begin
y:=edge[i].point;
if not v[y] then dfs(y);
i:=edge[i].next;
end;
end; begin
readln(n,m);
while (n<>) do
begin
ans:=;
len:=;
fillchar(p,sizeof(p),);
fillchar(a,sizeof(a),false);
for i:= to m do
begin
readln(x,y);
add(x,y);
a[x,y]:=true;
end;
for i:= to n do
begin
fillchar(v,sizeof(v),false);
dfs(i);
for j:= to n do
if v[j] and (i<>j) and not a[i,j] then
add(i,j);
end;
fillchar(cx,sizeof(cx),);
fillchar(cy,sizeof(cy),);
for i:= to n do
if cx[i]=- then
begin
fillchar(v,sizeof(v),false);
ans:=ans+find(i);
end;
writeln(n-ans);
readln(n,m);
end;
end.