Uva 11324 最大团

题目链接:http://vjudge.net/contest/141990#problem/B

题意:

给一张有向图G,求一个结点集数最大的结点集,是的该结点集中任意两个结点 u 和 v,满足: 要么 u 能到达 v,要么 v 能到达 u 或者 u 和 v 可以互达 ;

这个和有向强连通图很像,连通方式改了,强连通分量是 任意 两点 之间 都可以互达。可以发现一个强连通分量 ,要么全选,要么全部选。

思路:

把一个强连通分量看成一个结点,这个结点有权值,是他的大小,把每个强连通分量看成一个结点,这样 SCC 图就出来了,SCC图 他是一个有向无环图 DAG。

于是就可以用 dp 来做。

坑点:(数据有可能一个结点都没有)

#include <bits/stdc++.h>
using namespace std;

const int Maxn = 1000 + 10;

vector<int> G[Maxn];
int pre[Maxn];
int lowlink[Maxn];
int sccno[Maxn];
int dfs_clock;
int scc_cnt;
int n,m;

stack<int> S;

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)
{
    dfs_clock = scc_cnt = 0;
    memset(pre,0,sizeof(pre));
    memset(sccno,0,sizeof(sccno));

    for(int i=0; i<n; i++)
    {
        if(!pre[i])
            dfs(i);
    }
}

int size[Maxn], TG[Maxn][Maxn];
int d[Maxn];

int dp(int u)
{
    int& ans = d[u];
    if(ans >= 0) return ans;
    ans = size[u];
    for(int v = 1; v <= scc_cnt; v++)
        if(u != v && TG[u][v]) 
            ans = max(ans, dp(v) + size[u]);
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            G[i].clear();

        for(int i=0; i<m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            u--;
            v--;
            G[u].push_back(v);
        }

        find_scc(n);

        memset(size,0,sizeof(size));
        memset(TG,0,sizeof(TG));

        for(int i=0; i<n; i++)
        {
            size[sccno[i]] ++;
            for(int j=0; j<G[i].size(); j++)
            {
                TG[sccno[i]][sccno[G[i][j]]] = 1;
            }
        }
        int ans = 0;
        memset(d,-1,sizeof(d));
        for(int i=1; i<=scc_cnt; i++)
            ans = max(ans,dp(i));

        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TreeDream/p/6078965.html