树状DP+背包过的,得到的子树可以不包括根节点。写的垃圾,跑了600MS+。。。。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=155;
int first[maxn],vis[maxn],dp[maxn][maxn][2],in[maxn],f[maxn];
int N,P,size;
struct Edge
{
int v,next;
}edge[maxn];
void insert(int u,int v)
{
edge[size].v=v;
edge[size].next=first[u];
first[u]=size++;
}
void init()
{
memset(in,0,sizeof(in));
memset(first,-1,sizeof(first)); size=0;
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
dp[i][j][0]=dp[i][j][1]=maxn;
}
void dfs(int u)
{
if(first[u]==-1)
{
dp[u][1][1]=0;
return ;
}
int sub[maxn],cnt=0;
for(int e=first[u];e!=-1;e=edge[e].next)
{
int v=edge[e].v; sub[cnt++]=v;
dfs(v);
for(int j=1;j<=P;j++)
dp[u][j][0]=min(min(dp[v][j][1]+1,dp[v][j][0]),dp[u][j][0]);
}
for(int C=1;C<=P;C++)
{
for(int i=0;i<=P;i++) f[i]=maxn;
f[0]=0;
for(int i=0;i<cnt;i++)
{
int v=sub[i];
for(int c=C-1;c>=0;c--)
for(int j=1;j<=P;j++)
if(c-j>=0) f[c]=min(f[c],f[c-j]+dp[v][j][1]-1);
}
dp[u][C][1]=f[C-1]+cnt;
}
}
int main()
{
// freopen("test.txt","r",stdin);
scanf("%d%d",&N,&P);
init();
for(int i=0;i<N-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
insert(u,v); in[v]=1;
}
for(int u=1;u<=N;u++)
if(!in[u])
{
dfs(u);
printf("%d\n",min(dp[u][P][0],dp[u][P][1]));
break;
}
return 0;
}