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

来源:互联网 发布:怎么免费装修淘宝店铺 编辑:程序博客网 时间:2024/06/05 04:54

这题是点双连通分量,我一开始写成边的……

首先点双连通分量可能重叠……(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)       如果一个双连通分量含有奇圈,则他必定不是一个二分图。反过来也成立,这是一个充要条件。


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<b then exit(a) else exit(b);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         read(x,y);         b[x,y]:=false;         b[y,x]:=false;      end;      writeln(main);   end;end.


原创粉丝点击