uva 11324 The Largest Clique 强连通分量求缩点构造DAG

题目:uva 11324 The Largest Clique
从图中某点出发,求最远能够一次走过多少个节点

分析:
tarjan求gcc,然后构造出新图,新图是一个dag,对于dag上用dp求出最长路径即可。dp转移方程为dp[x] = size[x] + max(dp[y]); 缩点后有边x到y的边,记忆化搜索就行了,具体看实现代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>

using namespace std;

const int maxn = 1005;
const int maxm = 50005;

#define debug puts("here");

int dfn[maxn],low[maxn],stack[maxn],father[maxn],bcnt,top,depth;
bool instack[maxn];
int po[maxn],tol,n,m;
int id[maxn];
int dp[maxn];
int sum[maxn];

vector<int> vec[maxn];

struct node{
    int y,next;
}edge[maxm];

void add(int x,int y){
    edge[++tol].y = y;
    edge[tol].next = po[x];
    po[x] = tol;
}

void dfs(int x){	//递归实现tarjan算法
    low[x] = dfn[x] = ++depth;
    instack[x] = true;
    stack[++top] = x;
    int y;
    for(int i=po[x];i;i=edge[i].next){
        y = edge[i].y;
        if(!dfn[y]){
            dfs(y);
            low[x] = min(low[x],low[y]);
        }
        else if(instack[y])
            low[x] = min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x]){
        ++bcnt;
        do{
            y = stack[top--];
            instack[y] = false;
            father[y] = bcnt;
        }while(x!=y);
    }
}

void tarjan(){
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    top = bcnt = depth = 0;
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            dfs(i);
}

int f(int x){	//记忆化方法求dag上的最长路径
    if(dp[x])
        return dp[x];
    int ans = 0;
    for(int i=0;i<(int)vec[x].size();i++){	//从x的所有边出发,求出最大的路径
        int y = vec[x][i];
        ans = max(ans,f(y));	//转移方程
    }
    dp[x] = ans+sum[x];
    return dp[x];
}

void dag(){
    memset(id,0,sizeof(id));
    memset(sum,0,sizeof(sum));
    memset(dp,0,sizeof(dp));

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

    for(int x=1;x<=n;x++){		//构造新图
        for(int j=po[x];j;j=edge[j].next){
            int y = edge[j].y;
            if(father[x]!=father[y]){
                vec[father[x]].push_back(father[y]);
                id[father[y]] ++;
            }
        }
        sum[father[x]] ++;	//统计每个缩点后的该节点所包含的所有原图的节点数目
    }

    int ans = 0;
    for(int i=1;i<=bcnt;i++)
        if(!id[i])
            ans = max(f(i),ans);
    cout<<ans<<endl;
}

int main(){
    freopen("sum.in","r",stdin);
    int ncase;
    cin>>ncase;
    while(ncase--){
        cin>>n>>m;
        int x,y;
        memset(po,0,sizeof(po));
        tol = 0;
        while(m--){
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        tarjan();
        dag();
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/yejinru/p/2755616.html