匿年龄分组

 题目简述:

 BSNY所在的城市有N个人,每个人的年龄未知。已知M对人之间的年龄大小,用ai, bi表示编号ai的人的年龄不小于编号bi人的年龄。

为了让年龄更加隐匿,BSNY想把这N个人分成若干组,每组内的成员相互不能比较出年龄大小。

现在BSNY想知道,要达到上述要求,至少分多少组?

例如N=4, M=4。

M对关系如下:1不小于2,1不小于3,2不小于4,3不小于4

至少分3组:{1}, {2,3}, {4},使得每组内两两不能比较年龄

==================================================================================================

本来以为是没重构边才造成超时,其实是因为tarjan打错。。。

思路:tarjan缩点,同一环中的点都是年龄相同的,所以要分在不同组,再拓扑dp,dp[u]=max(dp[v])+count[u]

附代码:

var n,i,ii,m,j,k,l,tot,top,num,x,y,u,v,co,ans:longint; 
head,next,vet,h,nxt,vt,st,color,d,dfn,low,dp,count,dd:array[0..300005] of longint;

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(b);exit(a);end;

procedure tarjan(x:longint);
var i,v:longint;
begin
inc(num);low[x]:=num;dfn[x]:=num;
inc(top);st[top]:=x;
i:=head[x];
while i<>0 do begin
    v:=vet[i];
    if dfn[v]=0 then begin
        tarjan(v);
        low[x]:=min(low[x],low[v]);
        end else
    if color[v]=0 then low[x]:=min(low[x],dfn[v]);
    i:=next[i];
    end;
if dfn[x]=low[x] then begin
    inc(co);
    while st[top]<>x do begin
        inc(count[co]);
        color[st[top]]:=co;
                //write(st[top],' ');
        dec(top);
        end;
    inc(count[co]);
        //writeln(st[top]);
    color[st[top]]:=co;
    dec(top);
    end;
end;

function dfs(x:longint):longint;
var i,v,j,ii:longint;
begin
if dp[x]>0 then exit(dp[x]);
if d[x]=0 then begin dp[x]:=count[x];exit(dp[x]);end;
        ii:=h[x];
        while ii<>0 do begin
        v:=vt[ii];
        if v<>x then dp[x]:=max(dp[x],dfs(v));
        ii:=nxt[ii];
        end;
dp[x]:=dp[x]+count[x];
exit(dp[x]);
end;

begin
readln(n,m);
for i:=1 to m do begin
    readln(x,y);
    inc(tot);
    next[tot]:=head[x];
    head[x]:=tot;
    vet[tot]:=y;
    end;
tot:=0;
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[i]<>color[v] then begin
        inc(tot);nxt[tot]:=h[color[v]];h[color[v]]:=tot;vt[tot]:=color[i];
         inc(dd[color[i]]); inc(d[color[v]]);
        end;
        ii:=next[ii];
        end;
    end;
//for i:=1 to n do write(color[i],' ');writeln; 调代码的好方法
//for i:=1 to co do write(count[i],' ');writeln;
//for i:=1 to co do write(dd[i],' ');writeln;
//for i:=1 to co do write(d[i],' ');writeln;
for i:=1 to co do if dd[i]=0 then ans:=max(ans,dfs(i));
writeln(ans);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值