洛谷 U138543 湮灭的光
题目背景
“我揭开了未来的面纱,却只看到了湮灭”
题目描述
在预言中,夏古拉斯炸毁后,星灵不久后就惨遭灭亡。
为了避免自己族人灭亡,黑暗教长踏上了寻找其他预言碎片的道路。
星系中分布着N块预言碎片,黑暗教长的总体力值为M。收集碎片不是一件易事。收集第i块预言碎片将消耗黑暗教长Ti的体力值。 而这些充满神秘文字的碎片间存在依赖关系,对于预言碎片i,只有收集了其前置碎片Di时,黑暗教长才能获得这枚碎片的信息值Wi。(若Di=0,则说明该预言碎片无前置碎片。多块碎片可互相为前置碎片。)。也就是说,对于碎片i,若直接收集i而不收集Di,i将毫无贡献。
末日将近,时间紧迫。黑暗教长找到了JDOI的神——你。 他想知道在有限的体力内,能获得的最大信息值是多少
输入格式
第一行:N,M (0≤N≤100,0≤M≤500)
第二行:N个整数,表示Ti (0≤Ti≤M)
第三行:N个整数,表示Wi (0≤Wi≤1000)
第四行:N个整数,表示Di(0≤Di≤N,Di=i)
输出格式
一个整数 表示黑暗教长能获得的最大能量
题解:
2020.11.14模拟赛T4。
Tarjan缩点+建虚根树形DP
代码:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 505;
int n, m, cnt, w[maxn], a[maxn], d[maxn];
int dfn[maxn], low[maxn], bel[maxn], tot, scc, ins[maxn], sta[maxn], top;
int W[maxn], V[maxn], indag[maxn], dp[maxn][maxn];
struct edge {
int v;
edge *next;
}pool[maxn * 2], *head[maxn];
inline void add(int u, int v) {
edge *p = &pool[++cnt];
p->v = v, p->next = head[u], head[u] = p;
}
void tarjan(int u) {
dfn[u] = low[u] = ++tot; sta[++top] = u; ins[u] = 1;
for(edge *p = head[u]; p; p = p->next) {
int v = p->v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(ins[v])
low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
++scc;
while(sta[top + 1] != u) {
bel[sta[top]] = scc;
W[scc] += w[sta[top]];
V[scc] += a[sta[top]];
ins[sta[top--]] = 0;
}
}
}
void solve(int u)
{
for(int i = W[u]; i <= m; i++)
dp[u][i] = V[u];
for(edge *p = head[u]; p; p = p->next)
{
int v = p->v;
solve(v); int k = m - W[u];
for(int i = k; i >= 0; i--)
for(int j = 0; j <= i; j++)
dp[u][i + W[u]] = max(dp[u][i + W[u]], dp[v][j] + dp[u][i + W[u] - j]);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &w[i]);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
{
scanf("%d", &d[i]);
if(d[i])
add(d[i], i);
}
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
for(int i = 0; i <= n; i++)
head[i] = 0;
cnt = 0;
for(int i = 1; i <= n; i++)
if(bel[d[i]] != bel[i])
{
add(bel[d[i]], bel[i]);
indag[bel[i]]++;
}
for(int i = 1; i <= scc; i++)
if(!indag[i])
add(0, i);
solve(0);
printf("%d\n", dp[0][m]);
return 0;
}