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;
}
原文地址:https://www.cnblogs.com/tanhehe/p/3091570.html