这个题就是一个树形DP,输入处理有点恶心,RE好几次。其他要注意的地方我都标注释了
#include <stdio.h>
#include <string.h>
#include <math.h>
#define inf 1e9
typedef long long ll;
int n,m,k,cou;
char map[205][105];
int mon[205],head[205];
int dps[205][205];
struct point{
int to;
int next;
}leaf[40010];
int min(int a,int b){
return a>b?b:a;
}
int find(char * tem){
int i;
for(i=1;i<=k;i++){
if(strcmp(tem,map[i])==0){
return i;
}
}
strcpy(map[++k],tem);
return k;
}
void addedge(int a,int b){
leaf[cou].to=b;
leaf[cou].next=head[a];
head[a]=cou++;
}
int dp(int u){
int i,j,sum=0;
if(u)sum=1;
for(i=head[u];i!=-1;i=leaf[i].next){
sum+=dp(leaf[i].to);
}
for(i=head[u];i!=-1;i=leaf[i].next){
for(j=sum;j>=0;j--){ //注意01背包是逆向的
for(k=0;k<=j;k++){
if(dps[u][j-k]!=inf && dps[leaf[i].to][k]!=inf)
dps[u][j]=min(dps[u][j-k]+dps[leaf[i].to][k],dps[u][j]);
}
}
}
if(u)
dps[u][sum]=min(dps[u][sum],mon[u]);
return sum;
}
int main(){
char in[5],tem[105],flag[205];
int i,j,cur;
while(scanf("%s",in)&&in[0]!='#'){
sscanf(in,"%d",&n);
scanf("%d",&m);
k=0;
cou=0;
memset(head,-1,sizeof(head));
memset(flag,0,sizeof(flag));
for(i=1;i<=n;i++){
scanf("%s",tem);
int u=find(tem);
scanf("%d",&mon[u]);
while(scanf("%c",&tem[0]) && tem[0]!='\n'){
scanf("%s",tem);
int pp=find(tem);
flag[pp]=1;
addedge(u,pp);
}
}
for(i=1;i<=n;i++)
if(!flag[i])
addedge(0,i); // 0是根节点
for(i=0;i<=n;i++){
for(j=1;j<=n;j++)
dps[i][j]=inf;
dps[i][0]=0;
}
dp(0);
int ans=inf;
for(i=m;i<=n;i++) // 注意这里易漏
ans=min(ans,dps[0][i]);
printf("%d\n",ans);
}
}