uva 11324 The Largest Clique (强连通分量+dp)

本文介绍了一种解决有向图传递闭包中寻找最大团问题的方法。通过Tarjan算法找到强连通分量,并将其转化为求权值最大的路径问题。使用记忆化搜索算法来高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:给一个有向图,找出这个图的传递闭包的largest clique。

clique的定义是一个每对结点都有边相连的点集。

原图中的一个强连通分量,一定是传递闭包中的一个clique,因为强连通分量中的每对结点之间都相互可达。

用tarjan算法对原图求出强连通分量后进行缩点,构成了一个DAG(有向无环图)模型,此时问题就转化为了求一条权值最大的路径,每个点的权值即为这个点包含的点的个数,记忆化搜索就好了。

记忆化搜索时用dp[i]表示以结点i为终点的所有路径中的最大权值.


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define V 1005
#define E 50005
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;


int m,n,s[V],top,e,ct,scc,ct_scc[V],dfn[V],low[V];
int belong[V],dp[V],indeg[V],outdeg[V],head[V];
vector<int>mp[V];
bool vst[V];


struct Edge
{
    int to,next;
}edge[E];


void addedge(int u,int v)
{
    edge[e].to=v;
    edge[e].next=head[u];
    head[u]=e++;
}


void tarjan(int u)
{
    int v;
    s[top++]=u;
    dfn[u]=low[u]=++ct;
    vst[u]=1;
    int i;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].to;
        if(dfn[v]==0)
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vst[v] && low[u]>dfn[v])
            low[u]=dfn[v];
    }
    if(dfn[u]==low[u])
    {
        ++scc;
        do
        {
            v=s[--top];
            vst[v]=0;
            belong[v]=scc;
            ct_scc[scc]++;
        }while(u!=v);
    }
}


int d(int u)
{
    if(dp[u]!=-1) return dp[u];
    int len=mp[u].size();
    int i,mx=-1;
    for(i=0;i<len;i++)
    {
        mx=max(mx,d(mp[u][i]));
    }
    return dp[u]=mx+ct_scc[u];
}


int solve()
{
    int u;
    M(vst,0);M(dp,-1);M(indeg,0);M(outdeg,0);M(ct_scc,0);M(belong,0);M(dfn,0);M(low,0);
    for(u=1;u<=n;u++)
    {
        if(dfn[u]==0)
            tarjan(u);
    }
    int i;
    for(u=1;u<=n;u++)
    {
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(belong[u]!=belong[v])
            {
                mp[belong[v]].push_back(belong[u]);
                indeg[belong[v]]++;
                outdeg[belong[u]]++;
            }
        }
    }
    for(u=1;u<=scc;u++)
    {
        if(indeg[u]==0) dp[u]=ct_scc[u];
    }
    int ans=0;
    for(u=1;u<=scc;u++) ans=max(ans,d(u));
    return ans;
}


int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        top=0;
        e=0;ct=0;scc=0;
        scanf("%d%d",&n,&m);
        int i,a,b;
        for(i=0;i<=n;i++) mp[i].clear();
        M(head,-1);
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        printf("%d\n",solve());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值