题意:
给一个有n个结点的树,要去掉一些边分离出一棵恰有p个结点的子树,求去掉的最少边数。
思路:
树型dp,dp[root][x]表示root子树得到x个结点的子树需去掉的最少边数,设点root有num个孩子,那么经过num个阶段就能确定dp[root][x]的值,dp即可,用滚动数组节省空间。
代码:
//poj 1947
//sepNINE
#include <iostream>
using namespace std;
const int maxN=256;
int n,p;
int par[maxN],bro[maxN],son[maxN];
int dp[maxN][maxN];
void dfs(int root)
{
int i,j;
for(i=1;i<=p;++i)
dp[root][i]=100000;
dp[root][1]=0;
int s=son[root];
while(s){
dfs(s);
for(i=p;i>=1;--i){
dp[root][i]=dp[root][i]+1;
int tmp=dp[root][i];
for(j=1;j<i;++j)
tmp=min(tmp,dp[root][j]+dp[s][i-j]);
dp[root][i]=tmp;
}
s=bro[s];
}
return ;
}
int main()
{
scanf("%d%d",&n,&p);
int i,a,b;
memset(par,0,sizeof(par));
memset(bro,0,sizeof(bro));
memset(son,0,sizeof(son));
for(i=1;i<n;++i){
scanf("%d%d",&a,&b);
par[b]=1;
bro[b]=son[a];
son[a]=b;
}
int root;
for(i=1;i<=n;++i)
if(par[i]==0)
root=i;
dfs(root);
int ans=INT_MAX;
for(i=1;i<=n;++i)
if(par[i]==0)
ans=min(ans,dp[i][p]);
else
ans=min(ans,dp[i][p]+1);
printf("%d",ans);
}