Copy:

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

解题思路:u和v相互可达的时候,就是两个结点在同一个强连通分量内的时候 
首先要保证集合里面的点可达:强连通分量就满足集合内的点都相互可达。所以第一件事就是找出所有的强连通分量,并统计出每个强连通分量内的结点数

然后找出每个强连通分量之间的关系,也就是找出两个强连通分量之间的桥,连接可连接的强连通分量

最后将每个强连通分量收缩,得到SCC图。此时的SCC图就变成了一个DAG,所以题目就转成用DP求DAG了

 

#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1010
#define M 50010
using namespace std;
struct Edge
{
    int to, next;
};
Edge E[M];

stack<int> S;
int linklow[N], head[N], pre[N], num[N], sccno[N], dp[N];
int tot, dfs_clock, scc_cnt, n, m;
bool link[N][N];

void addEdge(int from, int to)
{
    E[tot].to=to;
    E[tot].next=head[from];
    head[from]=tot++;
}

void dfs(int u)
{
    linklow[u]=pre[u]= ++dfs_clock;
    S.push(u);
    
    for(int i=head[u]; i!=-1; i=E[i].next)
    {
        int v=E[i].to;
        if(!pre[v])
        {
            dfs(v);
            linklow[u]=min(linklow[u], linklow[v]);
        }
        else if(!sccno[v]) {
            linklow[u]=min(linklow[u], pre[v]);
        }
    }
    
    if(pre[u]==linklow[u])
    {
        scc_cnt++;
        num[scc_cnt]=0;
        while(1)
        {
            int x=S.top();
            S.pop();
            num[scc_cnt]++;
            sccno[x]=scc_cnt;
            if(x==u)
                break;
        }
    }
}

void find_SCC()
{
    memset(pre, 0, sizeof(pre)); 
    memset(sccno, 0, sizeof(sccno));
    dfs_clock=scc_cnt=0;
    
    for(int i=0; i<= n; i++)
        if(!pre[i])
            dfs(i);
}

int DP(int u)
{
    if(dp[u]) return dp[u];
    int Max=0;
    for(int i=1; i<=scc_cnt; i++)   //找桥 ; 
        if(i != u && link[u][i])
            Max=max(Max, DP(i));
    return dp[u]=Max+num[u];
}

void init()
{
    memset(head, -1, sizeof(head));
    tot=0;
    
    scanf("%d%d", &n, &m);
    if(n==0)
    {
        printf("0\n");
        return;
    }
    int u, v;
    for(int i=0; i<m; i++)
    {
        scanf("%d%d", &u, &v);
        addEdge(u, v);    
    } 
    find_SCC();
    memset(link, 0, sizeof(link));
    for(u=0; u<=n; u++)                 
    {
        for(int i=head[u]; i!=-1; i=E[i].next) {   //DAG ;
            v=E[i].to; 
            if(sccno[u] != sccno[v])
                link[sccno[u]][sccno[v]]=true;
        }
    }
    memset(dp, 0, sizeof(dp));
    int Max=0;
    for(int i=1; i<= scc_cnt; i++)
    {
        Max=max(Max, DP(i));
    }
    printf("%d\n", Max);
}
int main() { int T; scanf("%d", &T); while(T--) { init(); } return 0; }

 

posted on 2016-03-25 14:22  cleverbiger  阅读(175)  评论(0)    收藏  举报