题意:有一张 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\n",ans); 101 } 102 return 0; 103 }
时间: 2024-08-21 11:42:31