【UVA11324】 The Largest Clique (Tarjan+topsort/记忆化搜索)

UVA11324 The Largest Clique

题目描述

给你一张有向图 \(G\),求一个结点数最大的结点集,使得该结点集中的任意两个结点 \(u\)\(v\) 满足:要么 \(u\) 可以达 \(v\),要么 \(v\) 可以达 \(u\)\(u,v\)相互可达也行)。

输入输出格式

输入格式:

第一行:测试数据组数\(T\),每组数据的格式如下:
第一行为结点数 \(n\) 和边数 \(m\) ,结点编号 \(1~n\)
以下\(m\)行每行两个整数 \(u\)\(v\) ,表示一条有向边 \(u->v\)

输出格式:

每组数据输出最大结点集的结点数

输入输出样例

输入样例#1:

1
5 5
1 2
2 3
3 1
4 1
5 2

输出样例#1:

4

题解

首先,我们会想到\(Tarjan\)缩点,将缩成的点的\(siz\)大小当做点权。

因为缩完点之后就会是一个\(DAG\),所以可以跑DP。

这种题型有两种实现方式,\(topsort\)和记忆化搜索,代码中已注明。

转移就是\(dp[v]=max(dp[v],dp[u]+siz[v])\).

code:

#include
#include
#include
#include
#include
#include
#define R register
#define ll long long
#define N 1005
#define M 50005
using namespace std;
templateinline void read(T &a){
    char c=getchar();T x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    a=f*x;
}
int T,n,m,u[M],v[M],ru[N],siz[N],h[N],sta[N],low[N],dfn[N];
int top,num,tot,col[M],vis[N],dp[N],ans,cnt;
struct node{
    int nex,to;
}edge[M];
inline void add(R int u,R int v){
    edge[++tot].nex=h[u];
    edge[tot].to=v;
    h[u]=tot;
}
inline void Tarjan(R int x){
    dfn[x]=low[x]=++num;
    sta[++top]=x;vis[x]=1;
    for(R int i=h[x];i;i=edge[i].nex){
        R int xx=edge[i].to;
        if(!dfn[xx]){
            Tarjan(xx);
            low[x]=min(low[x],low[xx]);
        }
        else if(vis[xx])low[x]=min(low[x],dfn[xx]);
    }
    if(dfn[x]==low[x]){
        R int now=-1;
        cnt++;
        while(now!=x){
            now=sta[top];
            top--;
            col[now]=cnt;
            siz[cnt]++;
            vis[now]=0;
        }
    }
}
inline void init(){
    tot=num=top=ans=cnt=0;
    memset(h,0,sizeof(h));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(siz,0,sizeof(siz));
    memset(sta,0,sizeof(sta));
    memset(col,0,sizeof(col));
    memset(ru,0,sizeof(ru));
    memset(dp,-1,sizeof(dp));
}
inline void topsort(){
    queue q;
    while(!q.empty())q.pop();
    for(R int i=1;i<=cnt;i++)
        if(!ru[i])q.push(i),dp[i]=siz[i];
    while(!q.empty()){
        R int x=q.front();q.pop();
        for(R int i=h[x];i;i=edge[i].nex){
            R int xx=edge[i].to;
            dp[xx]=max(dp[x]+siz[xx],dp[xx]);
            --ru[xx];
            if(!ru[xx])q.push(xx);
        }
    }
}
inline int search(R int x){
    if(dp[x]!=-1)return dp[x];
    R int res=siz[x];
    for(R int i=h[x];i;i=edge[i].nex){
        R int xx=edge[i].to;
        res=max(search(xx)+siz[x],res);
    }
    return dp[x]=res;
}
int main(){
    read(T);
    while(T--){
        read(n);read(m);init();
        for(R int i=1;i<=m;i++)
            read(u[i]),read(v[i]),add(u[i],v[i]);
        for(R int i=1;i<=n;i++) 
            if(!dfn[i])Tarjan(i);
        tot=0;memset(h,0,sizeof(h));
        for(R int i=1;i<=m;i++)
            if(col[u[i]]!=col[v[i]])
                add(col[u[i]],col[v[i]]),ru[col[v[i]]]++;
        //记忆化搜索 
        for(R int i=1;i<=cnt;i++)
            ans=max(ans,search(i));
        //拓扑排序 
        topsort();
        for(R int i=1;i<=cnt;i++)
            ans=max(ans,dp[i]);
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(【UVA11324】 The Largest Clique (Tarjan+topsort/记忆化搜索))