POJ 2942(Tarjen的点双连通分量+交叉染色法)

2014-11-24 10:40:02 · 作者: · 浏览: 0

这题是点双连通分量,我一开始写成边的……
首先点双连通分量可能重叠……(1,2) (2,3) (3,1) (3,4) (4,5) (5,6) (3.6)
这时有(1,2,3)和(3,4,5,6)两组双连通分量
故一定要在Tarjen里判……另外Stack存边时注意特判(Stack不能为空)
当dfs[k]<=low[i] 时 就找到了点双连通分量 (这是点双连通)
请注意在推送(k,i)后遍历得到的一堆边(包括(k,i))组成了一组点双连通分量
两个重要定理:
(1) 如果一个双连通分量内的某些顶点在一个奇圈中(即双连通分量含有奇圈),那么这个双连通分量的其他顶点也在某个奇圈中;
(2) 如果一个双连通分量含有奇圈,则他必定不是一个二分图。反过来也成立,这是一个充要条件。

[delphi]
Program P2942;
const
maxn=1050;
maxm=1000000;
Var
n,m,i,j,x,y:longint;
b:array[1..maxn,1..maxn] of boolean;

color,c,dfs,low:array[1..maxn] of longint;

attend,flag:array[1..maxn] of boolean;

size,time,totssc:longint;

stack:array[0..maxm,1..2] of longint;

function min(a,b:longint):longint;
begin
if a end;
function is_Binary(k,col:longint):boolean;
var
i,j:longint;
begin
color[k]:=col;
for i:=1 to n do
if (flag[i]) and (b[k,i]) then
begin
if color[i]=0 then
begin
if not(is_binary(i,3-col)) then exit(false);
end
else
if color[k]=color[i] then exit(false);
end;

exit(true);
end;

procedure tarjen(k,father:longint);
var
i,j:longint;
begin
inc(time);
dfs[k]:=time;
low[k]:=time;

c[k]:=1;
for i:=1 to n do
if (b[k,i]) and (dfs[k]>dfs[i]) and (i<>father) then
begin
if dfs[i]=0 then
begin

inc(size);
stack[size,1]:=k;
stack[size,2]:=i;



tarjen(i,k);
low[k]:=min(low[k],low[i]);

if dfs[k]<=low[i] then
begin
fillchar(flag,sizeof(flag),false);
fillchar(color,sizeof(color),false);

while (size>0) do
begin
flag[stack[size,1]]:=true;
flag[stack[size,2]]:=true;
dec(size);
if (stack[size+1,1]=k) and (stack[size+1,2]=i) then break;

end;

if not(is_binary(k,1)) then
begin
for j:=1 to n do
if flag[j] then attend[j]:=true;


end;


end;


end
else
if c[i]=1 then low[k]:=min(low[k],dfs[i]);
end;





c[k]:=2;

end;


function main:longint;
var
i,j,tot:longint;
begin
fillchar(dfs,sizeof(dfs),0);
fillchar(low,sizeof(low),0);
fillchar(c,sizeof(c),0);
fillchar(attend,sizeof(attend),false);
fillchar(flag,sizeof(flag),false);
fillchar(color,sizeof(color),0);
fillchar(stack,sizeof(stack),0);
size:=0;time:=0;
for i:=1 to n do
if (dfs[i]=0) then
begin
tarjen(i,0);
end;

tot:=0;
for i:=1 to n do if attend[i] then inc(tot);
exit(n-tot);

end;

begin
while not seekeof do
begin
read(n,m);
if (n=0) and (m=0) then break;
fillchar(b,sizeof(b),true);
for i:=1 to n do b[i,i]:=false;
for i:=1 to m do
begin www.2cto.com
read(x,y);
b[x,y]:=false;
b[y,x]:=false;
end;
writeln(main);
end;
end.