一:【题意】
- 给定一棵树
- 放置恰好k个监听器
- 每个节点u仅当邻接点放置监听器,则u被监听
- 求所有节点被监听的方案数
二:【解法】
- 树上背包
- 对于每个节点,我们只关注子树中有几个监听器,是否被监听,是否放置监听器
- 所以我们设计dp[u][i][p][q]:u子树中选了i个点,u被监听的状态为p,u放置监听器的状态为q
- 我们枚举dp[u][i][p][q]和dp[v][j][p'][q']更新dp[u][i+j][p|q'][q]
- 树上背包复杂度O(nm)
三:【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;;
const int N=1e5+10,M=110,mod=1e9+7;
vector<int> mp[N];
int dp[N][M][2][2];int n,K;
int t[M][2][2];
int siz[N];
void Dp(int u,int fa){
siz[u]=1;
for(auto v:mp[u]){
if(v==fa) continue;
Dp(v,u);
}
dp[u][0][0][0]=1;dp[u][1][0][1]=1;
for(auto v:mp[u]){
if(v==fa) continue;
int up=min(siz[u]+siz[v],K);
for(int i=0;i<=min(K,siz[u]);i++)
for(int j=0;j<=siz[v]&&i+j<=up;j++)
for(int p=0;p<=1;p++)
for(int q=0;q<=1;q++)
for(int p1=0;p1<=1;p1++)
for(int q1=0;q1<=1;q1++){
if(q+p1==0) continue;
t[i+j][p|q1][q]+=1ll*dp[u][i][p][q]*dp[v][j][p1][q1]%mod;
t[i+j][p|q1][q]%=mod;
//cout<<u<<" "<<i+j<<" "<<(p|q1)<<" "<<q<<" "<<dp[u][i+j][p|q1][q]<<"\n";
}
for(int i=0;i<=up;i++)
for(int p=0;p<=1;p++)
for(int q=0;q<=1;q++){
dp[u][i][p][q]=t[i][p][q];
t[i][p][q]=0;
}
siz[u]=up;
}
}
int main(){
cin>>n>>K;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
mp[a].push_back(b);
mp[b].push_back(a);
}
Dp(1,1);
LL ans=1ll*dp[1][K][1][0]+dp[1][K][1][1];
ans%=mod;
cout<<ans<<"\n";
return 0;
}
//dp[u][i][p][q]:u选了i点,u被监听为p,u放监听器为q
//dp[u][i+j][p|q'][q]
//if q+p'!=0 dp[u][i][p][q]*dp[v][j][p'][q']