神奇树形dp
令f[i][j]表示以i为根的子树,必须选i,所得到大小为j的联通块的最小代价
具体转移不好说清楚,类似背包
答案的话,i如果不是根那么f[i][j]++
因为要和父亲断开
具体还是结合代码比较清晰
代码:
#include<bits/stdc++.h> using namespace std; const int N=205; int n,k; int ans=2147483647; int father[N],son[N]={0},s[N]; int f[N][N]; int hed[N<<1],tal[N<<1],nxt[N<<1],cnt=0; inline void addege(int x,int y){ cnt++; tal[cnt]=y; nxt[cnt]=hed[x]; hed[x]=cnt; } inline void dfs1(int u,int fa){ father[u]=fa; son[u]=1; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa) continue; s[u]++; dfs1(v,u); son[u]+=son[v]; } } inline void dfs(int u,int fa){ f[u][son[u]]=0; f[u][1]=s[u]; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa) continue; dfs(v,u); for(int l=son[u];l>=1;l--){ if(f[u][l]==f[0][0]) continue; for(int j=1;j<=son[u];j++){ if(f[v][j]==f[0][0]) continue; if(l+j>son[u]) continue;f[u][l+j]=min(f[u][l+j],f[v][j]+f[u][l]-1); } } } ans=min(ans,f[u][k]+(u==1?0:1)); // cout<<f[u][k]+(u==1?0:1)<<" "<<u<<endl; } int main(){ memset(f,127,sizeof(f)); //for(int i=1;i<N;i++) f[i][0]=0; scanf("%d%d",&n,&k); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); addege(x,y); addege(y,x); } dfs1(1,1); dfs(1,1); cout<<ans<<endl; return 0; }
原文:https://www.cnblogs.com/QYJ060604/p/11437844.html