tarjan缩点 洛谷3387

写这篇文章才发现我自己原来一直把tarjan拼成targin(targin对不起!)

这个缩点调了我两个多小时,最后还是看题解慢慢调对的。这个题其实题意很简单,就是求一个类似于最长路径的东西,那么首先我们可以把能够互相到达的点(即强连通分量)弄成一个点,重新建图,弄成一个有向无环图,然后在上面搜索(因为点少了很多而且没环)其中的艰辛其实很多,但是直接附上代码吧

#include
#include
#include
int p[100001]={0},dfn[100001]={0},s[100001]={0},co[100001]={0},nxt[100001]={0},dp[100001]={0};
int low[100001]={0},head[100001]={0},d[100001]={0},to[100001]={0},vis[100001]={0},x[100001]={0},y[100001]={0};
int n,m,tmp=0,num=0,top=0,col=0,max=-1;
int min(int x,int y)
{
    if(x>y)
      return y;
    else return x;
}
int add(int x,int y)
{
    tmp++;
    to[tmp]=y;
    nxt[tmp]=head[x];
    head[x]=tmp;
    return 0;
}
int targin(int i)
{
    int j,t;
    num++;top++;
    dfn[i]=num;low[i]=num;
    s[top]=i;
    for(j=head[i];j;j=nxt[j])
      {
      t=to[j];
      if(dfn[t]==0)
        {
        targin(t);
        low[i]=min(low[i],low[t]);
        }
      else if(co[t]==0)
        {
        low[i]=min(low[i],dfn[t]);
        }
      }
    if(dfn[i]==low[i])
      {
      col++;co[i]=col;
      while(s[top]!=i)
        {
        co[s[top]]=col;
        top--;
        }
      top--;
      }
    return 0;
}
int dfs(int i)
{
    int j,maxsum=0;
    if(dp[i]!=0)  return 0;
    dp[i]=d[i];
    for(j=head[i];j;j=nxt[j])
      {
      if(dp[to[j]]==0)
        dfs(to[j]);
      if(dp[to[j]]>maxsum)
        maxsum=dp[to[j]];
      }
    dp[i]+=maxsum;
    return 0;
}
int main()
{
    int i,j,t1,t2;
    memset(d,0,sizeof(d));
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
      scanf("%d",&p[i]);
    for(i=1;i<=m;i++)
      {
      scanf("%d%d",&x[i],&y[i]);
      if(x[i]!=y[i])
        add(x[i],y[i]);
      }
    for(i=1;i<=n;i++)
      if(dfn[i]==0)
        targin(i);
    for(i=1;i<=n;i++)
      d[co[i]]+=p[i];
    memset(nxt,0,sizeof(nxt));
    memset(to,0,sizeof(to));
    memset(head,0,sizeof(head));
    tmp=0;
    for(i=1;i<=m;i++)
      {
      if(co[x[i]]!=co[y[i]])
        add(co[x[i]],co[y[i]]);
      }
    for(i=1;i<=col;i++)
      if(dp[i]==0)
        {
        dfs(i);
        if(dp[i]>max)
          max=dp[i];
        }
    printf("%d",max);
    return 0;
}

(tarjan绝对是我开数组开的最多的一个算法)

你可能感兴趣的:(强连通分量)