Tarjan缩点模板 (洛谷P3387)
题目背景
缩点+DP
题目描述
给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
输入输出格式
输入格式:
第一行,n,m
第二行,n个整数,依次代表点权
第三至m+2行,每行两个整数u,v,表示u->v有一条有向边
输出格式:
共一行,最大的点权之和。
输入输出样例
说明
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 }