Tarjan求强联通分量

hihocoder1185

题意

中文题

分析

SCC后剩下的缩点都是scc[i]=i,若最后剩下n个点,并不一定是1~n

第一种:拓扑排序,对每一个点以其为终点的最大值

第二种:dfs记忆化搜索,对每一个点以其为起点的最大值

显然第二种更简单易写

dfs记忆化搜索

#include
using namespace std;
const int maxn =  1e5 + 5;
const int INF = 0x3f3f3f3f;

stack<int>s;
bool vis[maxn];
int dfn[maxn],low[maxn],scc[maxn],idx;
vector<int>g[maxn],newp[maxn];
int n,m,u,v,w[maxn],answer[maxn];

void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    s.push(u);
    vis[u]=true;
    int v;
    for(int i=0;ii){
        v=g[u][i];
        if(dfn[v]==0){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(vis[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
        do{
            v=s.top();
            s.pop();
            scc[v]=u;//指向根节点
            vis[v]=false;
        }while(u!=v);
}

void suodian()
{
    for(int i=1;i<=n;i++)
    {
        int len=g[i].size();
        for(int j=0;j)
        {
            int to=g[i][j];
            if(scc[i]==to||w[to]==0)
                continue;
            if(scc[to]!=to)
                w[scc[to]]+=w[to],w[to]=0;
            else newp[scc[i]].push_back(to);
        }
    }
}


int d[maxn];
int ans;

int dfs(int x)
{
    if(answer[x])
    {
        //cout<
        return answer[x];
    }

    int len=newp[x].size();
    if(len==0)
        return answer[x]=w[x];
    for(int i=0;i)
    {
        int to=newp[x][i];
        int t=dfs(to);
        answer[x]=max(answer[x],w[x]+answer[to]);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>w[i];
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        g[u].push_back(v);
    }
    for(int i=1;i<=n;i++)
        scc[i]=i;
    tarjan(1);
    suodian();
    memset(vis,false,sizeof(vis));
    dfs(scc[1]);
    printf("%d\n",answer[scc[1]]);
    return 0;
}
View Code

拓扑排序

#include
using namespace std;
const int maxn =  1e5 + 5;
const int INF = 0x3f3f3f3f;

stack<int>s;
bool vis[maxn];
int dfn[maxn],low[maxn],scc[maxn],idx;
vector<int>g[maxn],newp[maxn];
int n,m,u,v,w[maxn],answer[maxn];

void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    s.push(u);
    vis[u]=true;
    int v;
    for(int i=0;ii){
        v=g[u][i];
        if(dfn[v]==0){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(vis[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
        do{
            v=s.top();
            s.pop();
            scc[v]=u;//指向根节点
            vis[v]=false;
        }while(u!=v);
}

void suodian()
{
    for(int i=1;i<=n;i++)
    {
        int len=g[i].size();
        for(int j=0;j)
        {
            int to=g[i][j];
            if(scc[i]==to||w[to]==0)
                continue;
            if(scc[to]!=to)
                w[scc[to]]+=w[to],w[to]=0;
            else newp[scc[i]].push_back(to);
        }
    }
}


int d[maxn];

void dfs(int x)
{
    vis[x]=1;
    int len=newp[x].size();
    for(int i=0;i)
    {
        int to=newp[x][i];
        d[to]++;
        if(!vis[to])
        dfs(to);
    }
}
queue<int>q;
int ans;

void tpsort(int x)
{
    q.push(x);
    answer[x]=w[x];
    while(!q.empty())
    {
        //cout<<123<
        int now=q.front();
        q.pop();
        ans=max(ans,answer[now]);
        int len=newp[now].size();
        for(int i=0;i)
        {
            int to=newp[now][i];
           // cout<
            answer[to]=max(answer[to],w[to]+answer[now]); ///
            d[to]--;
            if(d[to]==0)
                q.push(to);
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>w[i];
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        g[u].push_back(v);
    }
    for(int i=1;i<=n;i++)
        scc[i]=i;
    tarjan(1);
    suodian();
    memset(vis,false,sizeof(vis));
    dfs(scc[1]);
    tpsort(scc[1]);
    printf("%d\n",ans);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Superwalker/p/8894071.html

你可能感兴趣的:(Tarjan求强联通分量)