Tarjan 缩点

//tarjan 缩点 
//把强连通分量染成同样的颜色 用数组记录一下强连通分量内所有点权和 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,cnt,ans,head[10001];
int t,sta[10001],vis[10001];
int dot,dfn[10001],low[10001];
int val[10001],a[200001],b[200001],ma[10001];
int    tot,col[10001],sum[10001]; 
struct uio{
    int to,next;
}edge[200001];
void add(int x,int y)
{
    edge[++cnt].next=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++dot;
    sta[++t]=x;
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].next)
    {
        int y=edge[i].to;
        if(!dfn[y])
        {
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])
            low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x])
    {
        tot++;
        while(sta[t+1]!=x) 
        {
            col[sta[t]]=tot;
            sum[tot]+=val[sta[t]];
            vis[sta[t]]=0;
            t--;
        }
    }
}
void get(int x)
{
    if(ma[x])
        return;
    ma[x]=sum[x];
    int manum=0;
    for(int i=head[x];i;i=edge[i].next)
    {
        int y=edge[i].to;
        if(!ma[y])
            get(y);
        manum=max(manum,ma[y]);
    }
    ma[x]+=manum;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        add(a[i],b[i]);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    memset(head,0,sizeof(head));
    memset(edge,0,sizeof(edge));
    cnt=0;
    for(int i=1;i<=m;i++)
        if(col[a[i]]!=col[b[i]])
            add(col[a[i]],col[b[i]]);
    for(int i=1;i<=tot;i++)
        if(!ma[i])
        {
            get(i);
            ans=max(ans,ma[i]);
        }
    printf("%d\n",ans);
     return 0;
}

猜你喜欢

转载自www.cnblogs.com/water-radish/p/9280529.html
今日推荐