zoukankan      html  css  js  c++  java
  • UVA11324 The Largest Clique(DP+SCC)

    题目链接

    题意:

    给一张有向图G,求一个结点数最大的结点集,使得该结点中任意两个结点 u 和 v满足:要么 u 可以到达 v, 要么 v 可以到达 u(u 和 v 相互可达也可以)。

    分析:

    ”同一个强连通分量中的点要么都选,要么不选。把强连通分量收缩点后得到SCC图,让每个SCC结点的权等于它的结点数,则题目转化为求SCC图上权最大的路径。由于SCC图是一个 DAG, 可以用动态规划求解。“

    注意:

    假设含有 n 个点的图中不含结点数大于 1 的强连通分量,那么缩点后的图含有 n 个点,由于 scc_cnt 是从 1 开始编号,所以初始化时要用<=n 而非 <n。

    for(int i=1; i<=n; i++) Map[i].clear(); 

    AC代码如下:

    #include <iostream>
    #include <vector>
    #include <stack>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    using namespace std;
    
    const int maxn = 1000+10;
    
    vector<int> G[maxn], Map[maxn];
    stack<int> S;
    int pre[maxn], lowlink[maxn], scc_cnt, sccno[maxn], dfs_clock, val[maxn], dp[maxn];
    
    void dfs(int u){
        pre[u] = lowlink[u] = ++dfs_clock;
        S.push(u);
        for(int i=0; i<G[u].size(); i++){
            int v = G[u][i];
            if(!pre[v]){
                dfs(v);
                lowlink[u] = min(lowlink[u], lowlink[v]);
            }
            else if(!sccno[v]){
                lowlink[u] = min(lowlink[u], pre[v]);
            }
        }
    
        if(lowlink[u] == pre[u]){
            scc_cnt++;
            for(;;){
                int x = S.top(); S.pop();
                sccno[x] = scc_cnt;
                if(x == u) break;
            }
        }
    }
    
    void find_scc(int n){
        scc_cnt = dfs_clock = 0;
        memset(pre, 0, sizeof(pre));
        memset(sccno, 0, sizeof(sccno));
        for(int i=0; i<n; i++){
            if(!pre[i]) dfs(i);
        }
    }
    
    int d(int x){
        if(dp[x]) return dp[x];
        else if(Map[x].size() == 0) return dp[x] = val[x];
    
        int ans = 0;
        for(int i=0; i<Map[x].size(); i++){
            ans = max(ans, d(Map[x][i]));
        }
        return dp[x] = ans+val[x];
    }
    
    int main(){
        int n, m, u, v, T;
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &m);
    
            memset(val, 0, sizeof(val));
            memset(dp, 0, sizeof(dp));
    
            for(int i=0; i<=n; i++) { G[i].clear(); Map[i].clear(); }   //这里要用<=
    
            for(int i=0; i<m; i++) {
                scanf("%d%d", &u, &v);
                u--; v--;
                G[u].push_back(v);
            }
    
            find_scc(n);
    
            //缩点
            for(int u=0; u<n; u++) {
                val[sccno[u]]++;
                for(int i=0; i<G[u].size(); i++){
                    int v = G[u][i];
                    if(sccno[v] != sccno[u]) Map[sccno[u]].push_back(sccno[v]);
                }
            }
    
            int ans = 0;
            for(int i=1; i<=scc_cnt; i++)
                ans = max(ans, d(i));
    
            printf("%d\n", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    【Redis】简介与安装
    【JAVA】 Java 连接池的工作原理
    【异常】ORA-01536: space quota exceeded for tablespace
    【Oracle】Oracle 序列步长问题
    【ORACLE】常用脚本
    【ORACLE】特殊的NULL
    【JAVA】Runtime
    【JAVA】Calendar
    出现脚本错误或者未正确调用 Page()
    小程序出现 “2 not found” 解决方案
  • 原文地址:https://www.cnblogs.com/tanhehe/p/3091570.html
Copyright © 2011-2022 走看看