这两天本来应该刷刷杭电的题,周末想着放松一下,就研究了一波入门哈希和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 */