ABC223 G - Vertex Deletion(换根dp)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ABC223 G - Vertex Deletion(换根dp)相关的知识,希望对你有一定的参考价值。
考虑定义 f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1]表示子树 i i i内能匹配的最大数目(状态 0 / 1 0/1 0/1表示节点 i i i是否被使用)
f f f数组做一遍树形 d p dp dp就可以得到.然后考虑换根,也就是当除掉点 u u u后整棵树的最大匹配数目
想要得到除去 u u u后的最大匹配数分为两部分,一个是 u u u子树内,这部分显然就是
∑ ( u , v ) max { f [ v ] [ 0 ] , f [ v ] [ 1 ] } \\sum\\limits_{(u,v)}\\max\\{\\ f[v][0],f[v][1]\\ \\} (u,v)∑max{ f[v][0],f[v][1] }
第二部分是以 u u u为根节点时往父亲节点延申的子树的最大匹配数记作 g [ u ] [ 0 / 1 ] g[u][0/1] g[u][0/1]
于是去掉节点 u u u的最大匹配数就是这两部分的和
考虑一个递推,也就是对于 u u u的儿子 v v v,能否处理出对应的 g [ v ] [ 0 ] , g [ v ] [ 1 ] g[v][0],g[v][1] g[v][0],g[v][1]
①.如果 v v v被使用,只能和 u u u匹配,此时的最大匹配数为
g [ u ] [ 0 ] + 1 + ∑ z ∈ s o n u & & z ! = v max ( f [ z ] [ 0 ] , f [ z ] [ 1 ] ) g[u][0]+1+\\sum\\limits_{z\\in son_u\\&\\&z!=v}\\max(f[z][0],f[z][1]) g[u][0]+1+z∈sonu&&z!=v∑max(f[z][0],f[z][1])
②.考虑如果 v v v不被使用,那么 u u u又分是否参与和儿子匹配两种情况
若 u u u不参与和儿子的匹配,显然最大匹配数为
max ( g [ u ] [ 0 ] , g [ u ] [ 1 ] ) + ∑ z ∈ s o n u & & z ! = v max ( f [ z ] [ 0 ] , f [ z ] [ 1 ] ) \\max(g[u][0],g[u][1])+\\sum\\limits_{z\\in son_u\\&\\&z!=v}\\max(f[z][0],f[z][1]) max(g[u][0],g[u][1])+z∈sonu&&z!=v∑max(f[z][0],f[z][1])
若 u u u参与和儿子的匹配,设和儿子 k k k匹配,最大匹配数为
g [ u ] [ 0 ] + 1 + f [ k ] [ 0 ] + ∑ z ∈ s o n u & & z ! = k & & z ! = v max { f [ z ] [ 0 ] , f [ z ] [ 1 ] } g[u][0]+1+f[k][0]+\\sum\\limits_{z\\in son_u\\&\\&z!=k\\&\\&z!=v}\\max\\{\\ f[z][0],f[z][1]\\ \\} g[u][0]+1+f[k][0]+z∈sonu&&z!=k&&z!=v∑max{ f[z][0],f[z][1] }
看上去记录一个最大值为 m x 1 mx_1 mx1来对节点 v v v转移就行了,但是如果此时 k = v k=v k=v怎么办??
所以还需要记录以下次大值 m x 2 mx_2 mx2,当转移节点 v v v可以作为最大转移节点,就是用 m x 2 mx_2 mx2来转移
至此,已经完成了数组 g g g的递推,我们只需要知道 g g g数组的初值
也就是 g [ 1 ] [ 0 ] = 0 , g [ 1 ] [ 1 ] = − i n f g[1][0]=0,g[1][1]=-inf g[1][0]=0,g[1][1]=−inf
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
const int maxn = 3e5+10;
int n,mx,ans,f[maxn][2];
vector<int>vec[maxn];
void dfs1(int u,int fa = 0)
{
bool flag = 1;
for(auto v:vec[u] )
{
if( v==fa ) continue;
dfs1( v,u ); flag = 0;
f[u][0] += max( f[v][0],f[v][1] );
}
for(auto v:vec[u] )
{
if( v==fa ) continue;
f[u][1] = max( f[u][1],f[u][0]-max( f[v][0],f[v][1] )+1+f[v][0] );
}
if( flag ) f[u][1] = -inf;//不可能
}
void dfs2(int u,int fa = 0,int f0 = 0,int f1 = -inf )
{
int now = 0;
for(auto v:vec[u] )
{
if( v==fa ) continue;
now += max( f[v][0],f[v][1] );
}
if( now+f0==mx ) ans++;
int mx1 = 0, mx2 = 0;
for(auto v:vec[u] )//节点u去匹配节点v时的最大和次大
{
int nw = 0;
if( v==fa ) continue;
nw = now+f0-max( f[v][0],f[v][1] )+f[v][0]+1;
if( nw>mx1 ) mx2 = mx1, mx1 = nw;
else if( nw>mx2 ) mx2 = nw;
}
for(auto v:vec[u] )
{
if( v==fa ) continue;
int nw = now+f0-max( f[v][0],f[v][1] )+f[v][0]+1;//当u,v匹配时
int z = max( f[v][0],f[v][1] );
int rx = now+f0+1-z;//(u,v)匹配起来
int ex = now+max(f0,f1)-z;//u不参与和儿子的匹配
if( nw==mx1 ) dfs2( v,u, max( ex,mx2-z ), rx );
else dfs2( v,u, max( ex,mx1-z ) ,rx );
}
}
int main()
{
cin >> n;
for(int i=2;i<=n;i++)
{
int l,r; cin >> l >> r;
vec[l].push_back( r ); vec[r].push_back( l );
}
dfs1( 1 );
mx = max( f[1][0],f[1][1] );
dfs2( 1 );
cout << ans;
}
以上是关于ABC223 G - Vertex Deletion(换根dp)的主要内容,如果未能解决你的问题,请参考以下文章