zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            read();
            findScc();
            solve();
        }
        return 0;
    }
    

      

  • 相关阅读:
    序列
    笔算开方法
    笔算开方法
    【AFO】闷声发大财
    P1092 虫食算[搜索]
    数据结构总结
    P1486 [NOI2004]郁闷的出纳员[权值线段树]
    P1850 换教室[dp+期望]
    P4281 [AHOI2008]紧急集合 / 聚会[LCA]
    P5021 赛道修建[贪心+二分]
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/4899150.html
Copyright © 2011-2022 走看看