
今天我们来讲Anti bribe & corruption 394 AtCoder Beginner Contest 394_F。这道题把我干成沙子了。
原题
题目描述
给定一棵包含 N N N 个顶点的无向树 T T T。顶点编号为 1 , 2 , ... , N 1, 2, \ldots, N 1,2,...,N,第 i i i 条边连接顶点 A i A_i Ai 和顶点 B i B_i Bi。
定义满足以下两个条件的图为烷烃:
- 该图是一棵无向树
- 所有顶点的度数为 1 1 1 或 4 4 4,且至少存在一个度数为 4 4 4 的顶点
请判断 T T T 中是否存在满足烷烃定义的子图。若存在,求此类子图的顶点数的最大值;否则输出 − 1 -1 −1。
输入格式
输入通过标准输入按以下格式给出:
N N N
A 1 A_1 A1 B 1 B_1 B1
A 2 A_2 A2 B 2 B_2 B2
⋮ \vdots ⋮
A N − 1 A_{N-1} AN−1 B N − 1 B_{N-1} BN−1
输出格式
若存在满足烷烃定义的子图,输出其顶点数的最大值;否则输出 − 1 -1 −1。
输入输出样例 #1
输入 #1
9
1 2
2 3
3 4
4 5
2 6
2 7
3 8
3 9
输出 #1
8
输入输出样例 #2
输入 #2
7
1 2
1 3
2 4
2 5
3 6
3 7
输出 #2
-1
输入输出样例 #3
输入 #3
15
8 5
2 9
1 12
6 11
9 3
15 1
7 12
7 13
10 5
6 9
5 1
1 9
4 5
6 14
输出 #3
11
说明/提示
约束条件
- 1 ≤ N ≤ 2 × 1 0 5 1 \leq N \leq 2 \times 10^5 1≤N≤2×105
- 1 ≤ A i , B i ≤ N 1 \leq A_i, B_i \leq N 1≤Ai,Bi≤N
- 输入的图是一棵无向树
- 所有输入值为整数
样例解释 1
选取顶点 1 , 2 , 3 , 4 , 6 , 7 , 8 , 9 1, 2, 3, 4, 6, 7, 8, 9 1,2,3,4,6,7,8,9 及边 ( 1 , 2 ) (1,2) (1,2)、 ( 2 , 3 ) (2,3) (2,3)、 ( 3 , 4 ) (3,4) (3,4)、 ( 2 , 6 ) (2,6) (2,6)、 ( 2 , 7 ) (2,7) (2,7)、 ( 3 , 8 ) (3,8) (3,8)、 ( 3 , 9 ) (3,9) (3,9) 构成的子图满足烷烃条件。其中顶点 2 2 2 和顶点 3 3 3 的度数为 4 4 4,其余顶点度数为 1 1 1,因此顶点数的最大值为 8 8 8。
翻译由 DeepSeek R1 完成
思路
这道题是一个树形 D P DP DP。
状态
d p u , i dp_{u,i} dpu,i 为以 u u u 为根节点,有 i i i 个子节点,最大节点个数。因为最多只能有四个,所以不会炸。
初始化
d p u , 0 dp_{u,0} dpu,0 是 1 1 1 就是它本身。其它的就为无穷小。
转移方程
d p u , i = m a x ( d p u , i , d p u , i − 1 + m a x ( d p v , 0 , d p v , 3 ) ) dp_{u,i}=max(dp_{u,i},dp_{u,i-1}+max(dp_{v,0},dp_{v,3})) dpu,i=max(dpu,i,dpu,i−1+max(dpv,0,dpv,3))。
也就是说它可以选择加这个儿子或不加。要加的话就必须从儿子有三个或零个子节点中选,不然就不满足要求。由此可以推出此方程
Code
cpp
#include<bits/stdc++.h>
using namespace std;
int n,h[414514],e[414514],ne[414514],idx,dp[414514][5],mx=-1;
void add(int u,int v){
e[idx]=v,ne[idx]=h[u],h[u]=idx++;
}
void dfs(int u,int pre){
dp[u][1]=-0x3f3f3f3f,dp[u][2]=-0x3f3f3f3f,dp[u][3]=-0x3f3f3f3f,dp[u][4]=-0x3f3f3f3f;
dp[u][0]=1;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==pre){
continue;
}
dfs(j,u);
for(int i=4;i>=1;i--){
dp[u][i]=max(dp[u][i],dp[u][i-1]+max(dp[j][0],dp[j][3]));
}
}
if(dp[u][1]>2){
mx=max(mx,dp[u][1]);
}
mx=max(mx,dp[u][4]);
}
int main(){
memset(h,-1,sizeof(h));
cin>>n;
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs(1,0);
cout<<mx;
return 0;
}
