最大匹配【树形DP】

>Link

ybtoj最大匹配


>Description

在这里插入图片描述
n ≤ 1 0 5 n\le 10^5 n105


>解题思路

麻掉了,考试的时候修改代码没修改完全,直接100变70 qwq

因为在树上匹配,我们可以树形DP
f i f_i fi 为第 i i i个节点的子树中的最大匹配, f f i = ∑ j ∈ s o n ( i ) f j ff_i=\sum_{j\in son(i)}f_j ffi=json(i)fj
如果选择一条边 ( u , v ) (u,v) (u,v) u u u v v v 的父亲, u u u v v v 周围的其它边都不能选择,那当前的价值就为 f f v + f f u − f v + 1 ff_v+ff_u-f_v+1 ffv+ffufv+1,因为 f v f_v fv 不能加上但是 f f u ff_u ffu 里面包含了,所以要减去

最大匹配的数量也一样,跟着最大匹配一起修改
g i g_i gi 为 … 的最大匹配数量, g g i = ∏ j ∈ s o n ( i ) g i gg_i=∏_{j\in son(i)}g_i ggi=json(i)gi
那 … 的情况下,方案数就为 g g v ∗ g g u / g v gg_v*gg_u/g_v ggvggu/gv,原理同上,因为要取模,所以要处理一下逆元


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define LL long long
using namespace std;

const LL Mod = 1e9 + 7;
struct edge
{
    
    
	int to, nxt;
} e[N * 2];
int T, P, n, cnt, h[N], f[N], ff[N], ans;
LL w[N], ww[N], answ;

void add (int u, int v)
{
    
    
	e[++cnt] = (edge){
    
    v, h[u]}; h[u] = cnt;
	e[++cnt] = (edge){
    
    u, h[v]}; h[v] = cnt;
}
LL power (LL aa, LL bb)
{
    
    
	if (!aa) return 1;
	LL ret = 1;
	aa %= Mod;
	for (; bb; bb >>= 1, aa = aa * aa % Mod)
	  if (bb & 1) ret = ret * aa % Mod;
	return ret;
}
void dfs (int now, int fath)
{
    
    
	int v, x = 0; LL y = 0;
	for (int i = h[now]; i; i = e[i].nxt)
	{
    
    
		v = e[i].to;
		if (v == fath) continue;
		dfs (v, now);
		ff[now] += f[v];
		ww[now] = ww[now] * w[v] % Mod;
	}
	f[now] = ff[now], w[now] = ww[now];
	for (int i = h[now]; i; i = e[i].nxt)
	{
    
    
		v = e[i].to;
		if (v == fath) continue;
		x = ff[v] + ff[now] - f[v] + 1;
		y = ww[v] * ww[now] % Mod * power (w[v], Mod - 2) % Mod;
		if (x > f[now]) f[now] = x, w[now] = y;
		else if (x == f[now]) w[now] = (w[now] + y) % Mod;
	}
}
void work ()
{
    
    
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++)
	  h[i] = f[i] = ff[i] = 0, w[i] = ww[i] = 1;
	ans = answ = cnt = 0;
	int u, v;
	for (int i = 1; i < n; i++)
	{
    
    
		scanf ("%d%d", &u, &v);
		add (u, v);
	}
	dfs (1, 0);
	if (f[1] > ans) ans = f[1], answ = w[1];
	else if (f[1] == ans && ans) answ = (answ + w[1]) % Mod;
	if (!ans) answ = 1;
	if (P == 1) printf ("%d\n", ans);
	else printf ("%d %lld\n", ans, answ);
}

int main()
{
    
    
	freopen ("hungary.in", "r", stdin);
	freopen ("hungary.out", "w", stdout);
	scanf ("%d%d", &T, &P);
	while (T--)
	  work ();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/121181791