【题解】洛谷P2515 & HAOI2010 软件安装

Link

题意

\(N\) 个点,总空间 \(M\) ,每个点占用空间 \(W_i\) ,价值 \(V_i\)​ 。每个点至多被一个点依赖。

选择一个点,当且仅当该点所有依赖(包括直接和间接)都被选择。求最大价值。

Solution

将依赖转为向被依赖的点连边。可以发现,处在同一个强连通分量里的点要么都选,要么都不选,于是考虑缩点。

缩点之后,考虑树上背包DP,新建一个空间、价值都为 \(0\) 的超级源点,向所有入度为 \(0\)​​ 的点连一条边,由于原先所有点出度均为 \(0\)\(1\)​ ,那么可以证明:如此操作后,图变为了一课有向树。(感性理解一波)

接着跑树上DP即可。

Code

这次的代码没用四个空格,用了tab,也许会出锅。。。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2 * 110, maxm = 2 * 510;
vector<int> e[maxn], e2[maxn];
int n, m, dfn[maxn], low[maxn], scc[maxn], tot, cnt, rd[maxn];
int f[maxn][maxm]; //f[i][j] 表示以 i 为根子树,剩余空间为 j 的最大价值
struct node
{
	int w, v;
} point[maxn];
int w[maxn], v[maxn];
stack<int> stk;
void tarjan(int x)
{
	dfn[x] = low[x] = ++cnt;
	stk.push(x);
	for (int i = 0; i < e[x].size(); i++)
	{
		int v = e[x][i];
		if (!dfn[v])
		{
			tarjan(v);
			low[x] = min(low[x], low[v]);
		}
		else if (!scc[v])
			low[x] = min(low[x], dfn[v]);
	}
	if (dfn[x] == low[x])
	{
		tot++;
		int tp = 0;
		while (tp != x)
		{
			tp = stk.top();
			stk.pop();
			scc[tp] = tot;
			w[tot] += point[tp].w;
			v[tot] += point[tp].v;
		}
	}
}
void dfs(int x)
{
	for (int i = w[x]; i <= m; i++)
	{
		f[x][i] = v[x];
	}
	for (int i = 0; i < e2[x].size(); i++)
	{
		int v = e2[x][i];
		dfs(v);
		for (int j = m; j >= w[x]; j--) // 枚举剩余空间
			for (int k = 0; k <= j - w[x]; k++) // 如果选择这个子树,可选的剩余空间为 0 ~ j - w[x]
				f[x][j] = max(f[x][j], f[x][j - k] + f[v][k]);
	}
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &point[i].w);
	for (int i = 1; i <= n; i++)
		scanf("%d", &point[i].v);
	int x;
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &x);
		if (x != 0)
			e[x].push_back(i);
	}
	for (int i = 1; i <= n; i++)
		if (!dfn[i])
			tarjan(i);
	for (int i = 1; i <= n; i++)
	{
		for (int j : e[i])
		{
			if (scc[i] != scc[j])
				e2[scc[i]].push_back(scc[j]), rd[scc[j]]++;
		}
	}
	for (int i = 1; i <= tot; i++)
		if (!rd[i])
			e2[0].push_back(i);
	dfs(0);
	int ans = 0;
	for (int i = 0; i <= m; i++)
		ans = max(f[0][m], ans);
	cout << ans << endl;
	return 0;
}
posted @ 2021-08-05 21:34  _slb  阅读(37)  评论(0编辑  收藏  举报