树形DP。这题折腾了一天,很开心,总算是独立AC了。题意读了好几遍,发现并不是很明确。
注意这个坑:即使该洞bug数为0,要获得该洞brain值,也需要至少一人经过该洞穴,但这个人可以不停留在这个点
估计这题代码我写的最长了。。。。有好多地方可以简化。。。
留几组数据:
第一组:答案是200
2 1
0 100
20 100
1 2
第二组:答案是100
2 1
20 100
0 100
1 2
第三组:答案是9
5 2
0 1
0 1
0 5
0 1
0 2
1 2
1 3
2 4
2 5
#include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<vector> #include<algorithm> using namespace std; const int maxn = 100 + 10; int dp[maxn][maxn]; int flag[maxn], tmp[maxn]; int n, m; int cost[maxn], val[maxn]; int c[maxn], w[maxn]; bool vis[maxn]; vector<int>tree[maxn]; vector<int>treeFlag[maxn]; void init() { for (int i = 0; i <= n; i++) tree[i].clear(); for (int i = 0; i <= n; i++) treeFlag[i].clear(); memset(dp, -1, sizeof dp); memset(vis, 0, sizeof vis); for (int i = 0; i <= n; i++) dp[i][0] = 0; } void read() { for (int i = 1; i <= n; i++) scanf("%d%d", &cost[i], &val[i]); for (int i = 1; i <= n - 1; i++) { int u, v; scanf("%d%d", &u, &v); tree[u].push_back(v); treeFlag[u].push_back(0); tree[v].push_back(u); treeFlag[v].push_back(0); } } void dfs(int now) { bool fail = 1; for (int i = 0; i<tree[now].size(); i++) if (!vis[tree[now][i]]) fail = 0; if (fail == 1) { int c; if (cost[now] % 20 == 0) c = cost[now] / 20; else c = cost[now] / 20 + 1; if (cost[now] == 0) c = 1; if (c <= m) dp[now][c] = val[now]; return; } for (int i = 0; i<tree[now].size(); i++) { if (!vis[tree[now][i]]) { vis[tree[now][i]] = 1; treeFlag[now][i] = 1; dfs(tree[now][i]); } } if (cost[now] != 0) { int costNow; if (cost[now] % 20 == 0) costNow = cost[now] / 20; else costNow = cost[now] / 20 + 1; memset(tmp, -1, sizeof tmp); tmp[0] = 0; for (int i = 0; i<tree[now].size(); i++) { if (!treeFlag[now][i]) continue; int u = 0; int id = tree[now][i]; for (int j = 1; j <= m - costNow; j++) if (dp[id][j] != -1) c[u] = j, w[u++] = dp[id][j]; memset(flag, -1, sizeof flag); flag[0] = 0; for (int k = 0; k<u; k++) { for (int j = m - costNow; j >= c[k]; j--) if (tmp[j - c[k]] != -1) if (tmp[j - c[k]] + w[k]>tmp[j] && tmp[j - c[k]] + w[k]>flag[j]) flag[j] = tmp[j - c[k]] + w[k]; } for (int j = 0; j <= m - costNow; j++) if (flag[j]>tmp[j]) tmp[j] = flag[j]; } for (int i = 0; i <= m - costNow; i++) if (tmp[i] != -1) dp[now][i + costNow] = tmp[i] + val[now]; } else { memset(tmp, -1, sizeof tmp); tmp[0] = 0; for (int i = 0; i<tree[now].size(); i++) { if (!treeFlag[now][i]) continue; int u = 0; int id = tree[now][i]; for (int j = 1; j <= m; j++) if (dp[id][j] != -1) c[u] = j, w[u++] = dp[id][j]; memset(flag, -1, sizeof flag); flag[0] = 0; for (int k = 0; k<u; k++) { for (int j = m; j >= c[k]; j--) if (tmp[j - c[k]] != -1) if (tmp[j - c[k]] + w[k]>tmp[j] && tmp[j - c[k]] + w[k]>flag[j]) flag[j] = tmp[j - c[k]] + w[k]; } for (int j = 0; j <= m; j++) if (flag[j]>tmp[j]) tmp[j] = flag[j]; } if (tmp[1] == -1) dp[now][1] = val[now]; else dp[now][1] = tmp[1] + val[now]; for (int i = 2; i <= m; i++) if (tmp[i] != -1) dp[now][i] = tmp[i] + val[now]; } } void work() { vis[1] = 1; dfs(1); int ans = 0; for (int i = 1; i <= m; i++) ans = max(ans, dp[1][i]); printf("%d ", ans); } int main() { while (~scanf("%d%d", &n, &m)) { if (n == -1 && m == -1) break; init(); read(); work(); } return 0; }