poj3160 强连通+记忆化搜索

题意:有一张 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 }
View Code
原文地址:https://www.cnblogs.com/cenariusxz/p/4817128.html