洛谷p2515 樹形DP + Tarjan
阿新 • • 發佈:2020-08-17
這兩天本來應該刷刷杭電的題,週末想著放鬆一下,就研究了一波入門雜湊和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\n",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 */