题目背景
缩点+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
/* 因为今天写了Tarjan呢,就做个Tarjan缩点加dp的题目 缩点将强联通分量缩成一个点 并查集合并,重新建点的权值一条边连接的两个点 不在一个并查集里就重新建边 之后dp就是一个DAG求最大路径了 */ #include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<queue> #define MAXN 100100 using namespace std; struct Edge{ int vi; int vj; int next; }edge[MAXN * 50]; int read() { int num = 0; char c = getchar(); while(c > '9' || c < '0')c = getchar(); while(c >= '0' && c <= '9') { num *= 10; num += c - '0'; c = getchar(); } return num; } int head[MAXN]; int dfn[MAXN]; int low[MAXN]; int father[MAXN]; int stack[MAXN]; int dp[MAXN]; bool visited[MAXN]; int quan[MAXN]; int quan2[MAXN]; int rudu[MAXN]; queue<int>q; int n,m; int cnt,now,top,ans,tot; void tarjan(int x) { dfn[x] = low[x] = ++cnt; visited[x] = true; stack[++top] = x; for(int i = head[x];i;i = edge[i].next) { int vj = edge[i].vj; if(!dfn[vj]) { tarjan(vj); low[x] = min(low[x],low[vj]); } else if(visited[vj]) { low[x] = min(low[x],dfn[vj]); } } if(low[x] == dfn[x]) { tot++; while(stack[top] != x) { father[stack[top]] = tot; quan2[tot] += quan[stack[top]]; visited[stack[top]] = false; top--; } father[stack[top]] = tot; quan2[tot] += quan[stack[top]]; visited[stack[top]] = false; top--; } } void push(int vi,int vj) { now++; edge[now].vi = vi; edge[now].vj = vj; edge[now].next = head[vi]; head[vi] = now; } int main() { n = read();m = read(); for(int i = 1;i <= n;i ++) quan[i] =read(); for(int i = 1;i <= m;i++) { int vi = read(); int vj = read(); push(vi,vj); } for(int i = 1;i <= n;i ++) if(!dfn[i]) tarjan(i); memset(head,0,sizeof(head)); for(int i = 1;i <= m;i ++) { int fa = father[edge[i].vi]; int fb = father[edge[i].vj]; if(fa != fb) { push(fa,fb); rudu[fb]++; } } for(int i = 1;i <= tot;i++) { ans = max(ans,quan2[i]); if(rudu[i] == 0) q.push(i),dp[i] += quan2[i]; } while(!q.empty()) { int op = q.front(); q.pop(); /*dp[op] += quan2[op]; ans = max(ans,dp[op]);*/ for(int i = head[op];i;i = edge[i].next) { int vj = edge[i].vj; dp[vj] = max(dp[vj],dp[op] + quan2[vj]); ans = max(ans,dp[vj]); rudu[vj]--; if(rudu[vj] == 0)q.push(vj); } } printf("%d",ans); return 0; }