UVA-11324 The Largest Clique (强连通+DP)

题目大意:在一张无向图中,最大的节点集使得集合内任意两个节点都能到达对方。

题目分析:找出所有的强连通分量,将每一个分量视作大节点,则原图变成了一张DAG。将每个分量中的节点个数作为节点权值,题目便转化为了在DAG中找一条有最大权值和的路径,可以DP解决。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<vector>
# include<stack>
# include<cstring>
# include<algorithm>
using namespace std;

const int maxn=1005;
int n,m,scc_cnt,dfs_cnt,pre[maxn],low[maxn],sccno[maxn],scc[maxn],dp[maxn];
vector<int>G[maxn],G1[maxn];
stack<int>S;

void read()
{
    int a,b;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i) G[i].clear();
    while(m--)
    {
        scanf("%d%d",&a,&b);
        --a,--b;
        G[a].push_back(b);
    }
}

void dfs(int u)
{
    low[u]=pre[u]=++dfs_cnt;
    S.push(u);
    for(int i=0;i<G[u].size();++i){
        int v=G[u][i];
        if(!pre[v]){
            dfs(v);
            low[u]=min(low[u],low[v]);
        }else if(!sccno[v])
            low[u]=min(low[u],pre[v]);
    }
    if(pre[u]==low[u]){
        ++scc_cnt;
        while(1)
        {
            int x=S.top();
            S.pop();
            ++scc[scc_cnt];
            sccno[x]=scc_cnt;
            if(x==u)
                break;
        }
    }
}

void findScc()
{
    dfs_cnt=scc_cnt=0;
    memset(pre,0,sizeof(pre));
    memset(low,0,sizeof(low));
    memset(scc,0,sizeof(scc));
    memset(sccno,0,sizeof(sccno));
    for(int i=0;i<n;++i) if(!pre[i])
        dfs(i);
}

int DP(int u)
{
    if(dp[u]!=-1)
        return dp[u];
    int res=0;
    for(int i=0;i<G1[u].size();++i){
        int v=G1[u][i];
        res=max(res,DP(v));
    }
    return dp[u]=scc[u]+res;
}

void solve()
{
    for(int i=0;i<=scc_cnt;++i)
        G1[i].clear();
    vector<int>::iterator it;
    for(int u=0;u<n;++u){
        for(int i=0;i<G[u].size();++i){
            int v=G[u][i];
            if(sccno[u]!=sccno[v]){
                it=find(G1[sccno[u]].begin(),G1[sccno[u]].end(),sccno[v]);
                if(it==G1[sccno[u]].end())
                    G1[sccno[u]].push_back(sccno[v]);
            }
        }
    }
    memset(dp,-1,sizeof(dp));
    int ans=0;
    for(int i=1;i<=scc_cnt;++i)
        ans=max(ans,DP(i));
    printf("%d\n",ans);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        read();
        findScc();
        solve();
    }
    return 0;
}

  

posted @ 2015-10-21 21:29  20143605  阅读(160)  评论(0编辑  收藏  举报