树形DP 01
树形DP
1、没有上司的舞会(选或不选)
题目描述
某大学有
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数
所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入格式
输入的第一行是一个整数
第
第
输出格式
输出一行一个整数代表最大的快乐指数。
样例 #1
样例输入 #1
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
样例输出 #1
5
提示
数据规模与约定
对于
思路
- 令
dp[u][0]
表示以u为根节点,不选u的最大快乐指数 - 令
dp[u][1]
表示以u为根节点,选u的最大快乐指数 - 通过
dfs
自根节点向下递,再从叶子节点网上归,传递转移最大值
代码
import sys
sys.setrecursionlimit(1000000)
input = lambda: sys.stdin.readline().strip()
r1 = lambda: int(input())
r2 = lambda: map(int, input().split())
r3 = lambda: [*map(int, input().split())]
def solve():
n = r1()
a = [0] * (n + 1)
for i in range(1,n + 1):
a[i] = r1()
g = [[] for _ in range(n + 1)]
st = [0] * (n + 1)
for _ in range(n - 1):
u,v = r2()
g[v].append(u)
st[u] = 1
root = 0
for i in range(1,n + 1):
if not st[i]:
root = i
break
dp = [[0,0] for _ in range(n + 1)]
def dfs(u):
dp[u][0] = 0
dp[u][1] = a[u]
for v in g[u]:
dfs(v)
dp[u][0] += max(dp[v][0],dp[v][1])
dp[u][1] += dp[v][0]
dfs(root)
print(max(dp[root][0],dp[root][1]))
if __name__ == "__main__":
t = 1
for _ in range(t):
solve()
2.Tree Painting(换根)
题面翻译
给定一棵
要求你做
第一次操作可以任意选点。
求可获得的最大权值。
题目描述
You are given a tree (an undirected connected acyclic graph) consisting of
Initially all vertices are white. On the first turn of the game you choose one vertex and paint it black. Then on each turn you choose a white vertex adjacent (connected by an edge) to any black vertex and paint it black.
Each time when you choose a vertex (even during the first turn), you gain the number of points equal to the size of the connected component consisting only of white vertices that contains the chosen vertex. The game ends when all vertices are painted black.
Let's see the following example:
Vertices
Your task is to maximize the number of points you gain.
输入格式
The first line contains an integer
Each of the next
It is guaranteed that the given edges form a tree.
输出格式
Print one integer — the maximum number of points you gain if you will play optimally.
样例 #1
样例输入 #1
9
1 2
2 3
2 5
2 6
1 4
4 9
9 7
9 8
样例输出 #1
36
样例 #2
样例输入 #2
5
1 2
1 3
2 4
2 5
样例输出 #2
14
提示
The first example tree is shown in the problem statement.
思路
- 理解题意,每次将一个白点涂成黑点加上的权值就是以这个点为根的子树大小,先用
dfs
求以1
为根的各节点尺寸大小 - 考虑
换根dp
,将u、v互换
,size[u],size[v] = n - size[v],n
,其余的都没改变,那么对答案的影响也就是u、v的尺寸大小变换。 - python
dfs
会爆栈与内存,改成bfs
即可!
代码(dfs)
import sys
sys.setrecursionlimit(1000000)
input = lambda: sys.stdin.readline().strip()
r1 = lambda: int(input())
r2 = lambda: map(int, input().split())
r3 = lambda: [*map(int, input().split())]
def solve():
n = r1()
g = [[] for _ in range(n + 1)]
for _ in range(n - 1):
u, v = r2()
g[u].append(v)
g[v].append(u)
size = [0] * (n + 1)
def dfs(u, fa):
size[u] = 1
for v in g[u]:
if v == fa:
continue
dfs(v, u)
size[u] += size[v]
dfs(1,0)
total = 0
for i in range(1,n + 1):
total+= size[i]
ans = 0
def reroot(u,fa,total):
nonlocal ans
for v in g[u]:
if v == fa:
continue
cnt1,cnt2 = size[u],size[v]
size[u],size[v] = n - size[v],n
ans = max(ans,total - (cnt2 - size[u]))
reroot(v,u,total - (cnt2 - size[u]))
size[u],size[v] = cnt1,cnt2
reroot(1,0,total)
print(ans)
if __name__ == "__main__":
t = 1
for _ in range(t):
solve()
3.城市环路
题目描述
一座城市,往往会被人们划分为几个区域,例如住宅区、商业区、工业区等等。
B 市就被分为了以下的两个区域——城市中心和城市郊区。在这两个区域的中间是一条围绕 B 市的环路,环路之内便是 B 市中心。
整个城市可以看做一个
现在,有一位名叫 Jim 的同学想在 B 市开店,但是任意一条边的
Jim 想尽量多的赚取利润,请问他应该在哪些地方开店?
输入格式
第一行一个整数
第二行有
接下来
最后一行有一个实数,代表常数
输出格式
输出一行一个实数代表答案,结果保留一位小数。
样例 #1
样例输入 #1
4
1 2 1 5
0 1
0 2
1 2
1 3
2
样例输出 #1
12.0
提示
数据规模与约定
- 对于
的数据,保证 。 - 另有
的数据,保证环上的点不超过 个。 - 对于
的数据,保证 , , , , 的小数点后最多有 位数字。
思路
-
找到树上的基环,可用并查集,拓扑排序,dfs
-
在基环上的取相邻两点,将环断开成普通树,再利用选或不选的常规树形DP思路即可
代码
import sys
sys.setrecursionlimit(1000000)
input = lambda: sys.stdin.readline().strip()
r1 = lambda: int(input())
r2 = lambda: map(int, input().split())
r3 = lambda: [*map(int, input().split())]
def solve():
n = r1()
a = r3()
g = [[] for _ in range(n)]
fa = [i for i in range(n)]
def find(x):
if x != fa[x]:
fa[x] = find(fa[x])
return fa[x]
p1, p2 = 0, 0
for _ in range(n):
u, v = r2()
fu, fv = find(u), find(v)
if fu == fv:
p1, p2 = u, v
continue
g[u].append(v)
g[v].append(u)
fa[fv] = fu
p = float(input())
dp = [[0, 0] for _ in range(n)]
def dfs(u, fa):
dp[u][0], dp[u][1] = 0,a[u]
for v in g[u]:
if v == fa:
continue
dfs(v,u)
dp[u][0] += max(dp[v][0],dp[v][1])
dp[u][1] += dp[v][0]
dfs(p1,-1)
ans = dp[p1][0]
dfs(p2,-1)
ans = max(ans,dp[p2][0])
print("%.1f" % (ans * p))
if __name__ == "__main__":
t = 1
for _ in range(t):
solve()
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期