UVA 11324 The Largest Clique(tarjan有向图强连通+缩点)

题意:给出一个有向图,问最多能有多少点能构成一个集合,这个集合性质是任意两点能相互到达,即u->v or v->y.

分析:任意两点能互相到达,而且是有向图,很容易想到是强连通。要使这个集合中的点最多,仅一个强连通分量肯定不行,可由多个强连通分量构成. 那么求出各个强连通分量后,缩点,然后深搜一次,找出最大点集。

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
using namespace std;
#define maxn 2002
#define inff 0x3FFFFFFF
int dfn[maxn],low[maxn],vis[maxn],succ[maxn],bic[maxn];
stack<int>sta;
vector<int>E[100000];
int tim,ans,maxx,cnt;
struct node
{
    int en,next;
}edge[100000];
int p[maxn],num;
void init()
{
    num=0;
    memset(p,-1,sizeof(p));
}
void add(int st,int en)
{
    edge[num].en=en;
    edge[num].next=p[st];
    p[st]=num++;
}
void tarjan(int u,int fa)
{
    low[u]=dfn[u]=++tim;
    vis[u]=1;
    sta.push(u);
    int j,v;
    for(j=p[u];j+1;j=edge[j].next)
    {
        v=edge[j].en;
//        if(v==fa)continue;//不判断父亲节点比如 1->2,2->1 他们在一个连通块
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else
            if(vis[v])
                low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        cnt++;
        while(!sta.empty())
        {
            int x=sta.top();
            sta.pop();
            succ[x]=cnt;
            vis[x]=0;
            if(x==u)break;
        }
    }
}
void dfs(int i,int temp)
{
    int j;
    int len=E[i].size();
     temp+=bic[i];
     ans=max(ans,temp);
    for(j=0;j<len;j++)
    {
        int v=E[i][j];
      dfs(v,temp);

    }
}
int main()
{
    int n,m,i,t,j;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        if(n==0){cout<<0<<endl;continue;}
        init();
        for(i=1;i<=m;i++)
        {
            int a,b;
            cin>>a>>b;
            add(a,b);
        }
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        memset(vis,0,sizeof(vis));
        memset(bic,0,sizeof(bic));
        tim=0;cnt=0;
        while(!sta.empty())sta.pop();

        for(i=1;i<=n;i++)
        {
            if(!dfn[i])
            {
                tarjan(i,-1);
            }
        }
        for(i=1;i<=n;i++)
        {
            bic[succ[i]]++;
        }
        for(i=0;i<100000;i++)E[i].clear();
        for(i=1;i<=n;i++)
        {
            for(j=p[i];j!=-1;j=edge[j].next)
            {
                int v=edge[j].en;
                if(succ[i]!=succ[v])

                    E[succ[i]].push_back(succ[v]);
            }
        }
        ans=0;
        for(i=1;i<=cnt;i++)
        {
           dfs(i,0);
        }

        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值