# poj3345 树型DP

for (k=0;k<g[x].size();k++)
{
y=g[x][k];
for (i=num[x];i>=0;i--)
for (j=0;j<=i && j<=num[y];j++)
if (dp[x][i-j]+dp[y][j]<dp[x][i])
dp[x][i]=dp[x][i-j]+dp[y][j];
}

x为根，y是儿子，dp[x][i]表示以x为根的子树取i个的最小代价。（最好先把儿子都遍历完后再dp，这样比较清楚）

#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
using namespace std;

const int maxn=205,oo=99999999;
vector<int> g[maxn];
int dp[maxn][maxn],v[maxn],num[maxn];
bool fa[maxn];
int n,m,id;

int dfs(int x)
{
num[x]=1;
int i,j,k,y;
for (k=0;k<g[x].size();k++)
{
y=g[x][k];
num[x]+=dfs(y);
}
for (k=0;k<=n;k++) dp[x][k]=oo;
dp[x][0]=0;
dp[x][num[x]]=v[x];
for (k=0;k<g[x].size();k++)
{
y=g[x][k];
for (i=num[x];i>=0;i--)
for (j=0;j<=i && j<=num[y];j++)
if (dp[x][i-j]+dp[y][j]<dp[x][i])
dp[x][i]=dp[x][i-j]+dp[y][j];
}
return num[x];
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
char str[1000];
int i,j,ans,now;
while (gets(str))
{
if (str[0]=='#') break;
sscanf(str,"%d%d",&n,&m);
map<string,int> wmap;
for (i=0;i<=n;i++)
g[i].clear();
memset(fa,0,sizeof(fa));
id=0;
for (i=1;i<=n;i++)
{
scanf("%s",str);
if (wmap.find(str)==wmap.end())
wmap[str]=++id;
now=wmap[str];
scanf("%d",&v[now]);
while (getchar()!='\n')
{
scanf("%s",str);
if (wmap.find(str)==wmap.end())
wmap[str]=++id;
g[now].push_back(wmap[str]);
fa[wmap[str]]=true;
}
}
v[0]=oo;
for (i=1;i<=n;i++)
{
if (fa[i]) continue;
g[0].push_back(i);
}
dfs(0);
ans=oo;
for (i=m;i<=n;i++)
if (dp[0][i]<ans) ans=dp[0][i];
printf("%d\n",ans);
}
return 0;
}