直接树形dp设(f[i][j][0/1][0/1])表示(i)子树,选了(j)个,(i被覆盖了吗),(选了i吗)
复杂度是(O(n*k^2))。
加上子树大小优化,复杂度降为(O(nk)),还有其它优化:
考虑度数为1的点,与它唯一相邻的点必须要选。
把必须要选的点找出来,如果(>k),则直接输出0。
进行了这个优化后,发现要合并的(>1)的子树不超过(k)个。
所以复杂度降为(O(nk+k^3))
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;
const int mo = 1e9 + 7;
const int N = 1e5 + 5;
int n, k, x, y, r[N];
vector<int> e[N];
#define pb push_back
#define si size()
int fa[N], siz[N];
int f[N][101][2][2];
ll g[101][2][2];
void dg(int x) {
siz[x] = 1;
f[x][0][0][0] = f[x][1][0][1] = 1;
ff(_y, 0, e[x].si) {
int y = e[x][_y]; if(y == fa[x]) continue;
fa[y] = x;
dg(y);
fo(i, 0, min(k, siz[x] + siz[y])) fo(j, 0, 1) fo(t, 0, 1) g[i][j][t] = 0;
fo(i, 0, siz[x]) fo(j, 0, 1) fo(t, 0, 1) if(f[x][i][j][t]) {
fo(p, 0, min(k - i, siz[y])) fo(q, !t, 1) fo(w, 0, 1) if(f[y][p][q][w]) {
g[i + p][j | w][t] = (g[i + p][j | w][t] + (ll) f[x][i][j][t] * f[y][p][q][w]) % mo;
}
}
siz[x] = min(k, siz[x] + siz[y]);
fo(i, 0, siz[x]) fo(j, 0, 1) fo(t, 0, 1)
f[x][i][j][t] = g[i][j][t] % mo;
}
}
int bz[N];
int main() {
scanf("%d %d", &n, &k);
fo(i, 1, n - 1) {
scanf("%d %d", &x, &y);
e[x].pb(y); e[y].pb(x);
r[x] ++, r[y] ++;
}
int cnt = 0;
fo(i, 1, n) if(r[i] == 1) {
bz[e[i][0]] = 1;
}
fo(i, 1, n) cnt += bz[i];
if(cnt > k) {
pp("0
");
return 0;
}
dg(1);
ll ans = ((ll) f[1][k][1][0] + f[1][k][1][1]) % mo;
pp("%lld
", ans);
}