题意:有一张 n 点 m 边的有向无环图,每个点有各自的权值,可正可负,现在从一个点开始走,一直走到不能走到其他点为止,每经过一个点,可以选择获得或不获得它的权值,每个点可以走多次,但是权值只能获得一次,问最后最多能够获得多少权值。
每个点可以走多次,权值只能获得一次,路过的时候权值可以不获得,所以我们只需要考虑正的权值就行了。在一个强连通分量中的点的权值我们都能获得,所以先缩点,得到一个有向无环图,然后从每个入度为 0 的点开始DFS,累计得到的最大权值就行。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 using namespace std;
6
7 const int maxn=3e4+5;
8 const int maxm=2e5+5;
9
10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn],num[maxn],id[maxn],v[maxn];
13 int dp[maxn];
14 stack<int>S;
15
16 int max(int a,int b){return a>b?a:b;}
17
18 void init(){
19 memset(head,-1,sizeof(head));
20 size[0]=size[1]=0;
21 memset(num,0,sizeof(num));
22 memset(id,0,sizeof(id));
23 memset(dp,-1,sizeof(dp));
24 }
25
26 void add(int a,int b,int c=0){
27 point[c][size[c]]=b;
28 nxt[c][size[c]]=head[c][a];
29 head[c][a]=size[c]++;
30 }
31
32 void dfs(int s){
33 stx[s]=low[s]=++t;
34 S.push(s);
35 for(int i=head[0][s];~i;i=nxt[0][i]){
36 int j=point[0][i];
37 if(!stx[j]){
38 dfs(j);
39 low[s]=min(low[s],low[j]);
40 }
41 else if(!scc[j]){
42 low[s]=min(low[s],stx[j]);
43 }
44 }
45 if(low[s]==stx[s]){
46 scccnt++;
47 while(1){
48 int u=S.top();S.pop();
49 scc[u]=scccnt;
50 num[scccnt]+=v[u]>0?v[u]:0;
51 if(s==u)break;
52 }
53 }
54 }
55
56 void setscc(){
57 memset(stx,0,sizeof(stx));
58 memset(scc,0,sizeof(scc));
59 t=scccnt=0;
60 for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
61 for(int i=1;i<=n;++i){
62 for(int j=head[0][i];~j;j=nxt[0][j]){
63 int k=point[0][j];
64 if(scc[i]!=scc[k]){
65 add(scc[i],scc[k],1);
66 id[scc[k]]++;
67 }
68 }
69 }
70 }
71
72 int dfs1(int s){
73 if(~dp[s])return dp[s];
74 int maxx=0;
75 for(int i=head[1][s];~i;i=nxt[1][i]){
76 int j=point[1][i];
77 maxx=max(maxx,dfs1(j));
78 }
79 dp[s]=maxx+num[s];
80 return dp[s];
81 }
82
83 int main(){
84 int m;
85 while(scanf("%d%d",&n,&m)!=EOF){
86 init();
87 for(int i=1;i<=n;++i)scanf("%d",&v[i]);
88 while(m--){
89 int a,b;
90 scanf("%d%d",&a,&b);
91 a++;
92 b++;
93 add(a,b);
94 }
95 setscc();
96 int ans=0;
97 for(int i=1;i<=scccnt;++i){
98 if(!id[i])ans=max(ans,dfs1(i));
99 }
100 printf("%d
",ans);
101 }
102 return 0;
103 }