模板缩点
Posted zbtrs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板缩点相关的知识,希望对你有一定的参考价值。
题目背景
缩点+DP
题目描述
给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
输入输出格式
输入格式:
第一行,n,m
第二行,n个整数,依次代表点权
第三至m+2行,每行两个整数u,v,表示u->v有一条有向边
输出格式:
共一行,最大的点权之和。
输入输出样例
说明
n<=10^4,m<=10^5,|点权|<=1000 算法:Tarjan缩点+DAGdp
#include <cstdio> #include <queue> #include <stack> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 10010, maxm = 100010; int n, m, head[maxn],sum[maxn],du[maxn], nextt[maxm], to[maxm], tot = 1, a[maxn], scc[maxn], top, pre[maxn], low[maxn], dfs_clock; int Head[maxn], To[maxn], Nextt[maxn], Tot = 1, d[maxn], vis[maxn], ans; void Add(int x, int y) { To[Tot] = y; Nextt[Tot] = Head[x]; Head[x] = Tot++; } void add(int x, int y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } stack <int> s; void tarjan(int u) { pre[u] = low[u] = ++dfs_clock; s.push(u); for (int i = head[u]; i; i = nextt[i]) { int v = to[i]; if (!pre[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (!scc[v]) low[u] = min(low[u], pre[v]); } if (pre[u] == low[u]) { top++; while (1) { int t = s.top(); s.pop(); scc[t] = top; sum[top] += a[t]; if (t == u) break; } } } void spfa(int s) { memset(d, 0, sizeof(d)); memset(vis, 0, sizeof(vis)); d[s] = sum[s]; vis[s] = 1; queue <int> q; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for (int i = Head[u]; i; i = Nextt[i]) { int v = To[i]; if (d[v] < d[u] + sum[v]) { d[v] = sum[v] + d[u]; if (!vis[v]) { vis[v] = 1; q.push(v); } } } } for (int i = 1; i <= top; i++) ans = max(ans, d[i]); } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); if (u != v) add(u, v); } for (int i = 1; i <= n; i++) if (!scc[i]) tarjan(i); for (int i = 1; i <= n; i++) for (int j = head[i]; j; j = nextt[j]) { int v = to[j]; if (scc[i] != scc[v]) { Add(scc[i], scc[v]); du[scc[v]]++; } } for (int i = 1; i <= top; i++) if (!du[i]) spfa(i); printf("%d\n", ans); return 0; }
以上是关于模板缩点的主要内容,如果未能解决你的问题,请参考以下文章