割点,桥,双连通

计算割点和桥数的模板:

(基本上和强连通的tarjan算法一样)

var n,m,i,j,k,l,num,top,tot,co,ii,x,y,u,v,count,ans,cutedge,root:longint;
head,next,vet,low,dfn,color,d:array[0..400005] of longint;
visit,st,cut:array[0..400005] of boolean;

function min(a,b:longint):longint;
begin if a

procedure add(x,y:longint);
begin
inc(tot);
next[tot]:=head[x];head[x]:=tot;
vet[tot]:=y;
inc(tot);
next[tot]:=head[y];head[y]:=tot;
vet[tot]:=x;
end;

procedure tarjan(x,fa:longint);
var i,v,son:longint;
    ok:boolean;
begin
inc(num);dfn[x]:=num;low[x]:=num;
son:=0;st[x]:=true;
i:=head[x];ok:=false;
while i<>0 do begin
    v:=vet[i];
    if (v=fa)and(not ok) then begin    //回边的处理
        ok:=true;i:=next[i];continue;
        end;
    if dfn[v]=0 then begin      //v易打错成i
        inc(son);
        tarjan(v,x);//相较于强连通算法,因为是无向图,所以要记录父亲节点
        if low[v]>dfn[x] then inc(cutedge);   //从v出发不能回到x及x以前,则为割边
        if low[v]>=dfn[x] then cut[x]:=true;    //从v出发不能回到x以前,则x为割点
        low[x]:=min(low[v],low[x]);//容易打错的地方,v,x要特别注意
        end
    else if st[v] then low[x]:=min(low[x],dfn[v]);
    i:=next[i];
    end;
if x=root then begin
    if son>1 then cut[x]:=true else cut[x]:=false;//根要特判
    end;
st[x]:=false;//搜索过后要复原,使下一次能被搜到
end;

begin
readln(n,m);
for i:=1 to m do begin
    readln(u,v);
    ADD(u,v);
    end;
for i:=1 to n do
    if dfn[i]=0 then begin root:=i;tarjan(i,0);end;
for i:=1 to n do if cut[i] then inc(count);
writeln(count,' ',cutedge);
end

计算要使整个图变成双连通需要加的边数:

基本思路:先将双连通分量缩成点,计算度为1的leaf节点数count,ans=(count+1)>>1

var n,m,i,j,k,l,num,top,tot,co,ii,x,y,u,v,count,ans:longint;

head,next,vet,op,low,dfn,color,d,st:array[0..30005] of longint;

visit:array[0..30005] of boolean;

 

function min(a,b:longint):longint;

begin if athen exit(a);exit(b);end;

 

procedure add(x,y:longint);

begin

inc(tot);

next[tot]:=head[x];head[x]:=tot;

vet[tot]:=y;op[tot]:=tot+1;

inc(tot);

next[tot]:=head[y];head[y]:=tot;

vet[tot]:=x;op[tot]:=tot-1;

end;

 

procedure tarjan(x:longint);

var i,v:longint;

begin

inc(num);dfn[x]:=num;low[x]:=num;

inc(top);st[top]:=x;

i:=head[x];

while i<>0 do begin

    if not visit[op[i]] then begin

        visit[i]:=true;

        v:=vet[i];

        if dfn[v]=0 then begin

            tarjan(v);

            low[x]:=min(low[x],low[v]);

            end

        else low[x]:=min(low[x],dfn[v]);

    end else visit[i]:=true;

    i:=next[i];

    end;

if dfn[x]=low[x] then begin  //边双连通

    inc(co);

    while st[top]<>x do begin

        color[st[top]]:=co;

        dec(top);

        end;

    color[st[top]]:=co;

    dec(top);

    end;

end;

 

begin

readln(n,m);

for i:=1 to m do begin

    readln(u,v);

    ADD(u,v);

    end;

for i:=1 to n do

    if dfn[i]=0 then tarjan(i);

for i:=1 to n do begin

    ii:=head[i];

    while ii<>0 do begin

        v:=vet[ii];

        if color[v]<>color[i] then

            inc(d[color[v]]);

        ii:=next[ii];

        end;

    end;

for i:=1 to co do if d[i]=1 then inc(count);

ans:=(count+1)>>1;

writeln(ans);

end.

你可能感兴趣的:(图论)