题目大意及思路:用最少的钱去收买m个国家,但国家这间有附属关系,如果收买了一个国家,它的附属国也被收买了,做法树形dp+背包,状态转移方程是:dp[u][k]=min(dp[u][k],dp[v][j]+dp[u][k-j]);
#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<string>
using namespace std;
const int maxn=205;
const int INF=1000000000;
int n,m;
int tot;
int dp[maxn][maxn];
vector<int>g[maxn];
map<string,int>rl;
int pay[maxn];
char s[maxn];
bool vis[maxn];
void init()
{
int i,j;
tot=1;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
dp[i][j]=INF;
for(i=0;i<=n;i++)
{
g[i].clear();
dp[i][0]=0;
}
memset(vis,0,sizeof(vis));
memset(pay,0,sizeof(pay));
rl.clear();
}
int Min(int a,int b){
if(a<b)return a;
return b;
}
int TreeDp(int u)
{
int i,j,k;
int num=0;
for(i=0;i<g[u].size();i++)
{
int v=g[u][i];
int sum=TreeDp(v);
num+=sum;
for(j=maxn-1;j>=0;j--)
for(k=0;k<=sum && k<=j ;k++)
{
dp[u][j]=Min(dp[u][j],dp[u][j-k]+dp[v][k]);
}
}
num++;
dp[u][num]=pay[u];
return num;
}
int main()
{
int i,j;
int val;
int v,u;
char tmp[maxn];
while(gets(tmp)!=NULL && tmp[0]!='#')
{
sscanf(tmp,"%d%d",&n,&m);
init();
for(i=1;i<=n;i++)
{
scanf("%s%d",s,&val);
if(rl.find(string(s))==rl.end())
rl[string(s)]=tot++;
u=rl[string(s)];
pay[u]=val;
while(getchar()!='\n')
{
scanf("%s",s);
if(rl.find(string(s))==rl.end())
rl[string(s)]=tot++;
v=rl[string(s)];
vis[v]=1;
g[u].push_back(v);
}
}
// puts("fffffffffff");
for(i=1;i<=n;i++)
if(!vis[i])
g[0].push_back(i);
TreeDp(0);
int ans=INF;
for(i=m;i<=n;i++)
if(ans>dp[0][i])
ans=dp[0][i];
printf("%d\n",ans);
}
return 0;
}