UVA11324 - The Largest Clique(强连通最大团)

Problem B: The Largest Clique

Given a directed graph G, consider the following transformation. First, create a new graphT(G) to have the same vertex set as G. Create a directed edge between two vertices u and v in T(G) if and only if there is a path between u and v in G that follows the directed edges only in the forward direction. This graph T(G) is often called the transitive closure of G.

We define a clique in a directed graph as a set of vertices U such that for any two vertices u and v in U, there is a directed edge either from u to v or from v to u (or both). The size of a clique is the number of vertices in the clique.

The number of cases is given on the first line of input. Each test case describes a graph G. It begins with a line of two integersn and m, where 0 ≤ n ≤ 1000 is the number of vertices of Gand 0 ≤ m ≤ 50,000 is the number of directed edges of G. The vertices of G are numbered from 1 to n. The following m lines contain two distinct integers u and vbetween 1 and n which define a directed edge from u to v in G.

For each test case, output a single integer that is the size of the largest clique in T(G).

Sample input

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

Output for sample input

4

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

思路:同一个强连通分量中的点要么都选,要么都不选。把强连通分量收缩点后得到SCC图,让每个SCC节点的权等于他的节点数,则题目转化为求SCC图上权最大的路径。可以用记忆化搜索搞。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define maxn 50080
#define maxm 200080
int first[maxn];
int nxt[maxm],vv[maxm];
int dfn[maxn],low[maxn],vis[maxn];
int S[maxn],c[maxn],sum[maxn];
int e,cnt,p,t;
int maxsum[maxn];
int n,m;
void addedge(int u,int v)
{
    vv[e] = v;  nxt[e] = first[u];  first[u] = e++;
}

void init()
{
    e = cnt = p = t = 0;
    memset(first,-1,sizeof(first));
    memset(dfn,0,sizeof(dfn));
    memset(vis,0,sizeof(vis));
    memset(sum,0,sizeof(sum));
    memset(maxsum,-1,sizeof(maxsum));
}

void Tarjan(int u)
{
    vis[u] = 1; S[++p] = u;
    dfn[u] = low[u] = ++cnt;
    for(int i = first[u];i != -1;i = nxt[i])
    {
        int v = vv[i];
        if(!dfn[v])
        {
            Tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(vis[v]) low[u] = min(low[u],dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        ++t;
        while(S[p] != u)
        {
            vis[S[p]] = 0;
            c[S[p]] = t;
            sum[t]++;
            p--;
        }
        vis[S[p]] = 0;  c[S[p]] = t;    p--;    sum[t]++;
    }
}

int dfs(int u)
{
    if(maxsum[u] != -1) return maxsum[u];//如果这个强连通分量已经确定了。
    maxsum[u] = sum[u];int add = 0;
    for(int i = 1;i <= n;i++)
    {
        if(c[i] == u)//如果这个点是这个强连通分量的
        {
            for(int j = first[i];j != -1;j = nxt[j])
            {
                int v = vv[j];
                int cv = c[v];
                if(u == cv) continue;
                add = max(add,dfs(cv));
            }
        }
    }
    maxsum[u] += add;
    return maxsum[u];
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i = 1;i <= m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if(u == v)  continue;
            addedge(u,v);
        }
        for(int i = 1;i <= n;i++)
            if(!dfn[i])
            {
                Tarjan(i);
            }
        int ans = 0;
        for(int i = 1;i <= t;i++)
            ans = max(ans,dfs(i));
        printf("%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值