Tarjan缩点模板 (洛谷P3387)

Posted mljkw-gsry

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tarjan缩点模板 (洛谷P3387)相关的知识,希望对你有一定的参考价值。

题目背景

缩点+DP

题目描述

给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

输入输出格式

输入格式:

 

第一行,n,m

第二行,n个整数,依次代表点权

第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

 

输出格式:

 

共一行,最大的点权之和。

 

输入输出样例

输入样例#1: 复制
2 2
1 1
1 2
2 1
输出样例#1: 复制
2

说明

n<=10^4,m<=10^5,|点权|<=1000 算法:Tarjan缩点+DAGdp

技术分享图片
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 #define maxn 100010
  6 using namespace std;
  7 inline int read()
  8 {
  9     int x=0,f=1;
 10     char ch=getchar();
 11     while(ch<0||ch>9)
 12     {
 13         if(ch==-) f=-1;
 14         ch=getchar();
 15     }
 16     while(ch>=0&&ch<=9)
 17     {
 18         x=x*10+ch-0;
 19         ch=getchar();
 20     }
 21     return x*f;
 22 }
 23 int head[maxn],ecnt,vis[maxn],dis[maxn],low[maxn],dfn[maxn],stk[maxn],tot,colortm,color[maxn],top,f[maxn],ans,w[maxn],x[maxn],y[maxn],n,m;
 24 struct edge
 25 {
 26     int u,v,next;
 27 }E[maxn];
 28 void add(int u,int v)
 29 {
 30     E[++ecnt].u=u;
 31     E[ecnt].v=v;
 32     E[ecnt].next=head[u];
 33     head[u]=ecnt;
 34 }
 35 void tarjan(int u)
 36 {
 37     vis[u]=1;
 38     stk[++top]=u;
 39     low[u]=dfn[u]=++tot;
 40     for(int i=head[u];i;i=E[i].next)
 41     {
 42         int v=E[i].v;
 43         if(!dfn[v])
 44         {
 45             tarjan(v);
 46             low[u]=min(low[u],low[v]);
 47         }
 48         else if(vis[v]) low[u]=min(low[u],dfn[v]);
 49     }
 50     if(dfn[u]==low[u])
 51     {
 52         ++colortm;
 53         vis[u]=0;
 54         while(stk[top+1]!=u)
 55         {
 56             vis[stk[top]]=0;
 57             color[stk[top]]=colortm;
 58             f[colortm]+=w[stk[top]];
 59             ans=max(ans,f[colortm]);
 60             top--;
 61         }
 62     }
 63 }
 64 void bfs(int x)
 65 {
 66     memset(vis,0,sizeof(vis));
 67     memset(dis,0,sizeof(dis));
 68     queue<int>q;
 69     q.push(x);
 70     vis[x]=1;
 71     dis[x]=f[x];
 72     while(!q.empty())
 73     {
 74         int u=q.front();
 75         for(int i=head[u];i;i=E[i].next)
 76         {
 77             int v=E[i].v;
 78             if(dis[v]<dis[u]+f[v])
 79             {
 80                 dis[v]=dis[u]+f[v];
 81                 if(!vis[v]) 
 82                 {
 83                     q.push(v);
 84                     vis[v]=1;
 85                 }
 86              } 
 87         }
 88         q.pop();
 89         vis[u]=0;
 90     }
 91     for(int i=1;i<=colortm;++i) ans=max(ans,dis[i]);
 92 }
 93 int main()
 94 {
 95     n=read();m=read();
 96     for(int i=1;i<=n;++i) w[i]=read();
 97     for(int i=1;i<=m;++i) 
 98     {
 99         int a=read(),b=read();
100         add(a,b);
101         x[i]=a;
102         y[i]=b;
103     }
104     for(int i=1;i<=n;++i)
105     {
106         if(!dfn[i]) tarjan(i);
107     }
108     memset(head,0,sizeof(head));
109     memset(E,0,sizeof(E));
110     ecnt=0;
111     for(int i=1;i<=m;++i)
112     {
113         if(color[x[i]]!=color[y[i]])
114         {
115             add(color[x[i]],color[y[i]]);
116         }
117     }
118     
119     for(int i=1;i<=colortm;++i)
120         bfs(i);
121     printf("%d\n",ans);
122     return 0;
123  } 
View Code

 

以上是关于Tarjan缩点模板 (洛谷P3387)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P3387 模板缩点

P3387 模板缩点(Tarjan求强连通分量)

洛谷 P3387 模板缩点

模板:tarjan缩点+重新建边+最短路

洛谷P3387 缩点模板

洛谷 P3387 模板缩点 题解