最大团问题

https://vjudge.net/problem/UVA-11324

把每个强连通分量缩成一个点,构造新图

在新图上搞个记忆化搜索

施工完毕

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int maxn = 1007;
stack<int>S;
int dfn[maxn], low[maxn], sccno[maxn], val[maxn], dp[maxn], scc_cnt, dfs_cnt;
vector<int>G[maxn], M[maxn];
void tarjan(int u){
    dfn[u] = low[u] = ++dfs_cnt;
    S.push(u);
    for(int i = 0; i < G[u].size(); i++){
        int v = G[u][i];
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(!sccno[v]){
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(low[u] == dfn[u]){
        scc_cnt++;
        while(1){
            int tmp = S.top();
            S.pop();
            sccno[tmp] = scc_cnt;
            if(tmp == u)
                break;
        }
    }
}
void findscc(int n){
    memset(dfn, 0, sizeof dfn);
    memset(sccno, 0, sizeof sccno);
    scc_cnt = dfs_cnt = 0;
    for(int i = 1; i <= n; i++){
        if(!dfn[i])
            tarjan(i);
    }
}
void test(int n){
    for(int i = 1; i <= n; i++){
        printf("%d ", sccno[i]);
    }
}
int treedp(int u){
    if(dp[u] != -1)
        return dp[u];
    dp[u] = val[u];
    int det = 0;
    for(int i = 0; i < M[u].size(); i++){
        int v = M[u][i];
        det = max(det, treedp(v));
    }
    dp[u] += det;
    return dp[u];
}
int solve(int n){
    memset(val, 0, sizeof val);
    for(int i = 1; i <= n; i++){
        val[sccno[i]]++;
    }
    for(int i = 1; i <= scc_cnt; i++)
        M[i].clear();
    for(int i = 1; i <= n; i++){
        for(int j = 0; j < G[i].size(); j++){
            int v = G[i][j];
            if(sccno[i] != sccno[v])
                M[sccno[i]].push_back(sccno[v]);
        }
    }
    memset(dp, -1, sizeof dp);
    int ans = 0;
    for(int i = 1; i <= scc_cnt; i++){
        if(dp[i] == -1){
            ans = max(ans, treedp(i));
        }
    }
    return ans;
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            G[i].clear();
        while(m--){
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
        }
        findscc(n);
        //test(n);
        printf("%d\n", solve(n));
    }
    return 0;
}

/*
4 5 5 1 2 2 3 3 1 4 1 5 2 5 5 1 2 2 3 3 1 4 1 5 2 5 5 1 2 2 3 3 1 4 1 5 2 5 5 1 2 2 3 3 1 4 1 5 2
*/

 

posted @ 2017-11-02 16:23  DearDongchen  阅读(450)  评论(0编辑  收藏  举报