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

来源:互联网 发布:淘宝怎么买药品 编辑:程序博客网 时间:2024/05/08 18:36

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 asG. Create a directed edge between two vertices u and v inT(G) if and only if there is a path between u and v inG that follows the directed edges only in the forward direction. This graphT(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 verticesu 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 graphG. 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 ofG. The vertices of G are numbered from 1 to n. The followingm lines contain two distinct integers u and vbetween 1 andn 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 inT(G).

Sample input

15 51 22 33 14 15 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 200080int 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 0