Codeforces 1032F Vasya and Maximum Matching
题目链接
http://codeforces.com/contest/1032/problem/F
题目大意
给你一棵 $n$ 个节点的树,可以删除任意条边,使得删除完之后的图仅有一种最大匹配的方法。问有多少种删边方法。
题目分析
考虑使用树形 $DP$ 来解决这道题。如果最大匹配的方法是唯一的,说明任意拆出来一条链都是偶数个点的。设 $f[x][0/1]$ 分别为点 $x$ 和儿子中的一个匹配上了,和没匹配上任何一个儿子。则显然有
$$f[x][1] = \prod{(f[y][0] + f[y][1])}$$
再来考虑 $f[x][0]$ 的转移方程。很明显,如果 $x$ 和它的一个儿子匹配上的话显然要选取儿子 $y$ 的 $f[y][1]$ 。其余的点 $0$ 和 $1$ 都可以选。注意到, $y$ 的儿子中已经匹配上的儿子和 $x$ 中其他已经匹配上的儿子是可以和它们连边的,因此需要考虑这种情况统计一下即可。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <vector> using namespace std; const int maxn = 3e5 + 5; long long mod = 998244353; int n, m, t; vector <int> e[maxn]; long long f[maxn][2]; long long g[maxn]; int read(){ int x; scanf("%d", &x); return x; } long long qpow(long long b, long long x){ long long ret = 1; while(x){ if(x & 1){ ret = ret * b % mod; } b = b * b % mod; x >>= 1; } return ret; } int addedge(int x, int y){ e[x].push_back(y); e[y].push_back(x); return 0; } int dfs(int x, int fa){ int y; int i, j; f[x][0] = 0; f[x][1] = 1; g[x] = 1; for(auto y : e[x]){ if(y != fa){ dfs(y, x); f[x][1] = f[x][1] * ((f[y][0] + f[y][1]) % mod) % mod; g[x] = g[x] * ((2 * f[y][0] + f[y][1]) % mod) % mod; } } for(auto y : e[x]){ if(y != fa){ f[x][0] = (f[x][0] + (g[x] * qpow((2 * f[y][0] + f[y][1]) % mod, mod - 2) % mod) * g[y] % mod) % mod; } } return 0; } int main(){ int i, j; int x, y; n = read(); for(i=1;i<n;i++){ x = read(); y = read(); addedge(x, y); } dfs(1, -1); printf("%lld\n", (f[1][0] + f[1][1]) % mod); return 0; }