洛谷p2515 树形DP + Tarjan

这两天本来应该刷刷杭电的题,周末想着放松一下,就研究了一波入门哈希和tarjan。

洛谷上找了这题,tarjan套个模板写得很快,这个再次建图加DP花了好多时间才看懂......

杭电的题来不及刷啦嘿嘿嘿 罗总在线催补题doge

说实话这题一上来思路比较清楚,然而tarjan之后还是照搬了不少题解区内容。

主要是tarjan结束后,通过belong以及依赖关系,直接反向建图,秀了我一脸。果然还是摆脱不了菜~

来个图好理解.png  ------------------------------------------------------------------------------------------------ 

题解的大部分都是参考红色数字再建图。                                                                                |

还看到一篇用floyd缩点的好像很有趣。那就学习一下floyd去了。hdu暂时拜拜hhh                 |

一想到明天周二 又要白给就很烦555                                                                                       |

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<string>
  5 #include<vector>
  6 #include<iomanip>
  7 #include<cstdio>
  8 
  9 #define INF 1e9
 10 using namespace std;
 11 int n, m;
 12 int t[110];
 13 int low[110];
 14 
 15 int cnt;
 16 int now;
 17 int stop;//
 18 int S[110];//模拟栈 
 19 bool instack[110];
 20 vector<int> v[110];
 21 
 22 int w[110];//cost
 23 int val[110];//value
 24 int rely[110];//依赖关系 
 25 
 26 vector<int> T[110];//记录强连通分量 
 27 int belong[110];//判断该点属于哪一强连通分量 
 28 
 29 int dp[110][510];//
 30 
 31 void initialize()
 32 {
 33     cnt = now = stop = 0;
 34     memset(instack, false, sizeof(instack));
 35     memset(t, 0, sizeof(t));
 36     memset(belong, 0, sizeof(belong)); 
 37     memset(dp, 0, sizeof(dp)); 
 38     for(int i = 0 ; i <= 100 ; i++){
 39         v[i].clear();
 40         T[i].clear();
 41     }
 42     
 43 }
 44 
 45 void tarjan(int x)
 46 {
 47     S[++stop] = x;//入栈 
 48     t[x] = low[x] = ++now;
 49     instack[x] = true;
 50     
 51     for(int i = 0 ; i < v[x].size() ; i++){
 52         int nxt = v[x][i];
 53         if(t[nxt]){
 54             if(instack[nxt] && t[nxt] < t[x]){
 55                 low[x] = t[nxt];//
 56             }
 57         }else{
 58             tarjan(nxt);
 59             low[x] = min(low[x], low[nxt]);
 60         }        
 61     }
 62     if(low[x] == t[x]){
 63         cnt++;
 64         int j;
 65         do{
 66             j = S[stop--];
 67             instack[j] = false;
 68             belong[j] = cnt;
 69         }while(j != x);        
 70     }
 71 }
 72 //f[u][i]为在节点u的子树内,费用限制为i的条件下能取到的最大价值
 73 void dfs_dp(int *cost, int *value, int u)////////
 74 {
 75     for(int i = cost[u] ; i <= m ; i++){
 76         dp[u][i] = value[u];//不是val[u]!! 此处下标已改为染色后 
 77     }
 78     for(int i = 0 ; i < T[u].size() ; i++){
 79         int v = T[u][i];
 80         dfs_dp(cost, value, v);
 81         for(int j = m - cost[u] ; j >= 0 ; j--){
 82             for(int q = 0 ; q <= j ; q++){
 83                 dp[u][j + cost[u]] = max(dp[u][j + cost[u]], dp[u][j + cost[u] - q] + dp[v][q]);
 84                 //后者:其他位置节省开支,允许u的子节点v得到部分分配                
 85             }            
 86         }
 87     }
 88 }
 89 
 90 void dp_solve()
 91 {        
 92     int cost[110], value[110];
 93     int check[110];
 94     for(int i = 0 ; i <= n ; i++){
 95         cost[i] = value[i] = check[i] = 0;
 96     }
 97     
 98     for(int i = 1 ; i <= n ; i++){
 99         cost[belong[i]] += w[i];
100         value[belong[i]] += val[i];//缩点
101         if(!rely[i] || belong[rely[i]] == belong[i])    continue;
102         T[belong[rely[i]]].push_back(belong[i]);///
103         check[belong[i]]++;
104     }
105     ///神仙之反向建边之花了好几个小时才看懂系列 
106     for(int i = 1 ; i <= n ; i++){
107         if(!check[belong[i]]){
108             T[0].push_back(belong[i]);
109         }
110     }//无头则连至虚拟节点 
111     
112     dfs_dp(cost, value, 0);
113     
114     printf("%d
",dp[0][m]);
115 }
116 
117 int main(){
118     scanf("%d%d",&n,&m);
119     for(int i = 1 ; i <= n ; i++){
120         scanf("%d",&w[i]);
121     }
122     
123     for(int i = 1 ; i <= n ; i++){
124         scanf("%d",&val[i]);
125     }
126     
127     initialize();
128     
129     for(int i = 1 ; i <= n ; i++){
130         scanf("%d",&rely[i]);
131         if(rely[i]){
132             v[rely[i]].push_back(i);//建边
133         }
134     }
135     
136     for(int i = 1 ; i <= n ; i++){
137         if(!t[i]){
138             tarjan(i);        
139         }
140     }    
141     dp_solve();
142     
143     return 0;
144 }
145 /*
146 12 2
147 1 1 1 1 1 1 1 1 1 1 11 1
148 1 1 1 11 1 1 1 1 1 1 1 1
149 0 1 1 1 4 4 5 10 8 9 0 11
150 */
原文地址:https://www.cnblogs.com/ecustlegendn324/p/13517922.html