【CCPC】2021威海站 H. city safety | 树形DP

189 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【CCPC】2021威海站 H. city safety | 树形DP

题目链接

Problem - H - Codeforces

题目

Country X is a prosperous free-trade country, which has n cities connected by n−1 bidirectional roads. Although country X has been very stable, businessmen are generally very sensitive to the safety of cities. They hope country X can strengthen public security forces to ensure the safety of cities.

In addition, businessmen are also concerned about the safety of the surrounding areas. Therefore, if the security force in a city is strengthened, but the security force in the nearby cities are not strengthened, they will still be worried about the threat in nearby cities.

Formally, to strengthen the security force in city i, a cost of wiw_i should be paid. Such effort is not in vain, as more businessmen will be attracted and country X will benefit from it. If every city with a distance from city i less or equal to p is strengthened, the city i will gain vpv_p more income than before. (if more than one p satisfy the condition, only the maximum one is considered.)

Now you, as the country's officer, are appointed to deal with this problem. Your goal is to get the maximum benefit (the increased income minus the cost of strengthening the security force).

题目大意

有一棵 nn 个节点的树,如果想点亮第 ii 个节点,需要花费 wiw_i 点代价,如果距离一个节点不超过 pp 的所有节点都被点亮了,该节点可以取得 vpv_p 点收益。你可以决定是否点亮每一个节点,最大化总收益减总代价。

思路

树形DP。(据说可以最小割但是我不会)

画图观察可知如果 ii 节点能获得 vpv_p 点收益,那么与 ii 相邻的节点获得的收益一定属于 {vp,vp+1,vp1}\{vp,vp+1,vp−1\}。 且与 ii 相邻的节点这三种取值相互独立互不影响。

以随便一个节点为根节点把整棵树拎起来,令 dp[u][i]dp[u][i] 表示以节点 uu 的收益为 viv_i 时,以 uu 为根节点的子树的最大收益。除了不点亮 uu 的情况外的其他方案需要减去 wuw_u,加上 viv_i。先递归对其子节点求解后,再令 dp[u][i]dp[u][i] 加上子节点三种可能的取值的最大值即可。

枚举根节点所有可能的收益,统计答案。

代码

#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
using LL=long long;
const int N=205;
int n;
LL wst[N],val[N],dp[N][N];
vector<int> e[N];
void dfs(int u,int fa)
{
	for (int i=1;i<=n;++i) dp[u][i]=val[i]-wst[u];
	for (auto v:e[u])
	{
		if (v==fa) continue;
		dfs(v,u);
		for (int i=1;i<n;++i)
			dp[u][i]+=max({dp[v][i-1],dp[v][i],dp[v][i+1]});
		dp[u][0]+=max(dp[v][0],dp[v][1]);
		dp[u][n]+=max(dp[v][n-1],dp[v][n]);
	}
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i) scanf("%d",&wst[i]);
	for (int i=1;i<=n;++i) scanf("%d",&val[i]);
	for (int i=1,x,y;i<n;++i)
	{
		scanf("%d%d",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(1,0);
	LL ans=0;
	for (int i=0;i<=n;++i) ans=max(ans,dp[1][i]);
	printf("%lld\n",ans);
}