矿产搭建

在错误十一次后终于对了

高兴的附代码:

const maxx=100005;

var o,root,u,v,x,y,n,m,i,j,k,l,tot,num,top,flag,co:longint;

ans,anss:int64;

dfn,low,head,next,vet,st,count,cutd:array[0..100005] of int64;

cut:array[0..100005] of boolean;

 

procedure clear;

var i:longint;

begin

tot:=0;num:=0;top:=0;n:=0;co:=0;inc(o);ans:=0;anss:=1;

for i:=1 to maxx do dfn[i]:=0;

for i:=1 to maxx do low[i]:=0;

for i:=1 to maxx do count[i]:=0;

for i:=1 to maxx do cutd[i]:=0;

for i:=1 to maxx do head[i]:=0;

for i:=1 to maxx do cut[i]:=false;

end;

 

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

begin if a>b then exit(b);exit(a);end;

 

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

begin if a>b then exit(a);exit(b);end;

 

procedure build(x,y:longint);

begin

inc(tot);next[tot]:=head[x];head[x]:=tot;vet[tot]:=y;

end;

 

procedure tarjan(u:longint);

var i,v,son:longint;

begin

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

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

son:=0;

i:=head[u];

while i<>0 do begin

    v:=vet[i];

    if dfn[v]=0 then begin

        inc(son);

        tarjan(v);

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

        if (root=u)and(son>1)or(u<>root)and(low[v]>=dfn[u]) then cut[u]:=true;

        if  dfn[u]<=low[v] then begin

            inc(co);

            repeat

            inc(count[co]); //write(st[top],' ');

            if cut[st[top]] then inc(cutd[co]);

            dec(top);

            until st[top+1]=v;

            inc(count[co]);

            if cut[u] then inc(cutd[co]);// writeln(u);

            if (u=root)and(not cut[u]) then flag:=co;

            end;

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

    i:=next[i];

    end;

end;

 

begin

readln(m);

while m<>0 do begin

    clear;

    for i:=1 to m do begin

        readln(u,v);

        build(u,v);

        build(v,u);

        n:=max(n,max(u,v));

        end;

    for i:=1 to n do if dfn[i]=0 then begin flag:=0; root:=i; tarjan(i);if (cut[root]) then inc(cutd[flag]);end;

    for i:=1 to co do if cutd[i]=1 then begin inc(ans);anss:=anss*(count[i]-1);end

        else if cutd[i]=0 then begin inc(ans,2);anss:=(anss*count[i]*(count[i]-1))>>1;end;

    writeln('Case ',o,': ',ans,' ',anss);

        //for i:=1 to n do if cut[i] then write(i,' ');writeln;

    readln(m);

    end;

end.

关键部分已经标出,找连通块,和强连通等的判断条件(dfn[u]=low[u])不同,这只要判含有v的连通块分支

第一次做以为把连通块都找出后(st[top+1]=v)就有st[top]=u了其实不然,但u还是要加入到这个连通块中的。

边tarjan边count有一个不好,就是根(root)可能在第一次搜的时候还不是cut点,所以要flag标记,看根后来有没有变成连通块。root只可能在一个连通块(block)中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值