洛谷 P3387 模板缩点 题解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P3387 模板缩点 题解相关的知识,希望对你有一定的参考价值。
此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
题目链接:https://www.luogu.org/problem/show?pid=3387
题目背景
缩点+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
AC代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 #include<stack> 7 8 const int MAXN = 2000005; 9 inline void read(int &x) 10 { 11 char ch = getchar(),c = ch;x = 0; 12 while(ch < ‘0‘ || ch > ‘9‘) c = ch,ch = getchar(); 13 while(ch <= ‘9‘ && ch >= ‘0‘) x = (x<<1)+(x<<3)+ch-‘0‘,ch = getchar(); 14 if(c == ‘-‘) x = -x; 15 } 16 17 int n,m,v,cnt,dfn_cnt,part,ans; 18 int head[MAXN],val[MAXN],dfn[MAXN],low[MAXN]; 19 int belong[MAXN],sum[MAXN],f[MAXN],t[MAXN]; 20 int vis[MAXN],dp[MAXN]; 21 22 struct Edge 23 { 24 int f,t,nxt; 25 }e[MAXN]; 26 27 void insert(int f,int t) 28 { 29 e[++cnt].f = f,e[cnt].t = t; 30 e[cnt].nxt = head[f]; 31 head[f] = cnt; 32 } 33 34 inline int Min(int a,int b) 35 {return a<b?a:b;} 36 37 inline int Max(int a,int b) 38 {return a>b?a:b;} 39 40 std::stack <int> s; 41 42 void tarjan(int u) 43 { 44 dfn[u] = low[u] = ++dfn_cnt; 45 s.push(u); 46 for(int i = head[u];i;i = e[i].nxt) 47 { 48 int v = e[i].t; 49 if(!dfn[v]){ 50 tarjan(v); 51 low[u] = Min(low[v],low[u]); 52 } 53 else if(!belong[v]) 54 low[u] = Min(low[u],dfn[v]); 55 } 56 if(dfn[u] == low[u]) 57 { 58 ++ part; 59 while(!s.empty()) 60 { 61 int tmp = s.top(); 62 s.pop(); 63 belong[tmp] = part; 64 sum[part] += val[tmp]; 65 if(tmp == u) break; 66 } 67 } 68 } 69 70 int dfs(int u) 71 { 72 if(dp[u]) return dp[u]; 73 dp[u] = sum[u]; 74 int mx = 0; 75 for(int i = head[u];i;i = e[i].nxt) 76 { 77 int t = e[i].t; 78 if(!dp[t]) dfs(t); 79 if(dp[t] > mx) mx = dp[t]; 80 } 81 dp[u] += mx; 82 return dp[u]; 83 } 84 85 int main() 86 { 87 read(n),read(m); 88 for(int i = 1;i <= n;++ i) 89 read(val[i]); 90 for(int i = 1;i <= m;++ i) 91 { 92 read(f[i]),read(t[i]); 93 insert(f[i],t[i]); 94 } 95 //Tarjan缩点 96 for(int i = 1;i <= n;++ i) 97 if(!dfn[i]) 98 tarjan(i); 99 memset(head,0,sizeof(head)); 100 memset(vis,0,sizeof(vis)); 101 memset(e,0,sizeof(e)); 102 cnt = 0; 103 //重新建图 104 for(int i = 1;i <= m;++ i) 105 if(belong[f[i]] != belong[t[i]]) 106 insert(belong[f[i]],belong[t[i]]); 107 //DAG DP 108 for(int i = 1;i <= part;++ i) 109 { 110 if(!dp[i]){ 111 dfs(i); 112 ans = Max(ans,dp[i]); 113 } 114 } 115 printf("%d\n",ans); 116 return 0; 117 }
以上是关于洛谷 P3387 模板缩点 题解的主要内容,如果未能解决你的问题,请参考以下文章