Luogu 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 //2018年4月30日17:48:17
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int N = 100001;
 8 const int M = 500001;
 9 
10 int n, m, w[N], ans;
11 
12 int fir[N], to[M], nxt[M], edge_num;
13 void addEdge(int x, int y){
14     to[++edge_num] = y;
15     nxt[edge_num] = fir[x];
16     fir[x] = edge_num; 
17 }
18 
19 int dfn[N], low[N], stack[N], top, instack[N], tim, col_num, color[N], sum[N];
20 void Tarjan(int x){
21     low[x] = dfn[x] = ++tim;
22     stack[++top] = x;
23     instack[x] = 1;
24     for(int i=fir[x]; i; i=nxt[i]){
25         int v = to[i];
26         if(!dfn[v]){
27             Tarjan(v);
28             low[x] = min(low[x], low[v]);
29         }else if(instack[v]){
30             low[x] = min(low[x], dfn[v]);
31         }
32     }
33     if(low[x] == dfn[x]){
34         col_num++;
35         while(1){
36             int now = stack[top--];
37             instack[now] = 0;
38             color[now] = col_num;
39             sum[col_num] += w[now];
40             if(now == x) break; 
41         }
42     }
43 }
44 
45 int dp[N];
46 
47 int dfs(int u){
48     if(dp[u]) return dp[u];
49     dp[u] = sum[u];
50     int mx = 0;
51     for(int i=fir[u]; i; i=nxt[i]){
52         int v = to[i];
53         if(!dp[v]) dfs(v);
54         if(dp[v] > mx) mx = dp[v]; 
55     }
56     dp[u] += mx;
57     return dp[u];
58 }
59 
60 int main(){
61     scanf("%d%d", &n, &m);
62     for(int i=1; i<=n; i++)
63         scanf("%d", &w[i]);
64     int x[N], y[N]; 
65     for(int i=1; i<=m; i++){
66         scanf("%d%d", &x[i], &y[i]);
67         addEdge(x[i], y[i]); 
68     }
69     for(int i=1; i<=n; i++)
70         if(!dfn[i])
71             Tarjan(i);
72     memset(fir, 0, sizeof(fir));
73     memset(to, 0, sizeof(to));
74     memset(nxt, 0, sizeof(nxt));
75     edge_num = 0;
76     for(int i=1; i<=m; i++)
77         if(color[x[i]] != color[y[i]])
78             addEdge(color[x[i]], color[y[i]]);
79     for(int i=1; i<=col_num; i++)
80         if(!dp[i]){
81             dfs(i);
82             ans = max(ans, dp[i]);
83         }
84     printf("%d\n", ans);
85 
86     return 0;
87 }

 

转载于:https://www.cnblogs.com/sineagle/p/8974235.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值