习题:Vasya and Maximum Matching(转换&DP)
题目
思路
这道题的难点主要在于模型的转换
我们首先考虑一颗树的如果有唯一最大匹配会满足什么条件
每一个叶子是一个被匹配到的(这应该不难证明吧)
接着我们考虑将每一对匹配的节点删去,那么最后一定不会剩下任何节点(你可以平移的思想去证明)
当然,还是有唯一的例外的,这个树只有一个节点
接着我们设\(dp[i][3]\)表示以i为根节点的子树,0表示i已经和某一个儿子匹配了,1表示i不和任何一个儿子进行匹配,但是他与父亲进行了匹配,2表示i不和任何一个儿子进行匹配,这里不要求和父亲之间的关系
接着我们考虑用插入的方法来合并dp,即将v节点前面所枚举的节点看做是一颗子树
如果是0,那么他可能之前就已经匹配好,或者是与v进行匹配
如果是1,那么儿子节点要么匹配好了,要么就是一个点或者自己以前就是无子的情况
如果是2,就更简单了,直接考虑儿子匹配好了,或者无子就行
代码
#include<iostream>
#include<vector>
using namespace std;
const int mod=998244353;
int n;
long long dp[300005][3];
/*
0:匹配
1:未被匹配,但是父亲和他进行匹配
2:无子
*/
long long temp[3];
vector<int> g[300005];
void dfs(int u,int fa)
{
dp[u][2]=1;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
dfs(v,u);
temp[0]=dp[u][0]*(dp[v][0]*2+dp[v][2])%mod;
temp[0]=(temp[0]+(dp[u][1]+dp[u][2])*(dp[v][1]+dp[v][2])%mod)%mod;
temp[1]=dp[u][2]*dp[v][0]%mod;
temp[1]=(temp[1]+dp[u][1]*(dp[v][0]*2+dp[v][2]))%mod;
temp[2]=(dp[u][2]*(dp[v][2]+dp[v][0]))%mod;
for(int j=0;j<=2;j++)
dp[u][j]=temp[j];
}
}
}
int main()
{
cin>>n;
for(int i=1,u,v;i<n;i++)
{
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
cout<<(dp[1][0]+dp[1][2])%mod;
return 0;
}

浙公网安备 33010602011771号