Tree DP。由于选定某棵子树的根之后,所有的子节点都被选择。我们先处理出不考虑树根的情况,选择j个点所需要的最小花费。然后对于每个j进行判断,如果对应的价值大于树根的价值,就更新。直接看代码:
/*
*author : csuchenan
*PROG : POJ3345
*Algorithm : Tree DP dp[i][j]表示以i为根节点选取j个点所有需要的最小代价
*notice : 读入时需要注意,用STL的会比较好写一点,对于dp[i][j]的值计算的时候
* 需要注意
*csuchenan 3345 Accepted 416K 16MS C++ 2416B
*/
#include <cstdio>
#include <cstring>
#include <vector>
#include <sstream>
#include <iostream>
using std::stringstream ;
using std::vector ;
using std::cin ;
#define maxn 205
#define INF 0x3f3f3f3f
int val[maxn] ;
int num[maxn] ;
char name[maxn][105] ;
int dp[maxn][maxn] ;
vector<int> G[maxn] ;
int n , m ;
int len ;
int insert(char * str){
len ++ ;
strcpy(name[len] , str) ;
return len ;
}
int find(char * str){
int i = 0;
for( ; i <= len && strcmp(str , name[i])!=0 ; i ++) ;
return i > len ? -1 : i ;
}
void init(){
for(int i = 0 ; i <= n ; i ++){
G[i].clear() ;
}
memset(dp , 0x3f , sizeof(dp)) ;
memset(num , 0 , sizeof(num)) ;
len = 0 ;
}
bool read(){
char str[1005] ;
char tmp[105] ;
cin.getline(str , sizeof(str)) ;
if(str[0] == '#')
return 0 ;
int p , q ;
int cnt ;
sscanf(str , "%d%d" , &n , &m) ;
init() ;
for(int i = 0 ; i < n ; i ++){
scanf("%s%d" , tmp , &p) ;
if( (q = find(tmp)) == -1 )
q = insert(tmp) ;
val[q] = p ;
cin.getline(str , sizeof(str)) ;
stringstream ss(str) ;
while(ss>>tmp){
if((p = find(tmp))==-1)
p = insert(tmp) ;
G[q].push_back(p) ;
num[p] ++ ;
}
}
return 1 ;
}
int dfs(int v){
int cnt = 1 ;
for(int i = 0 ; i != G[v].size() ; i ++){
int u = G[v][i] ;
cnt += dfs(u) ;
}
dp[v][0] = 0 ;
for(int i = 0 ; i != G[v].size() ; i ++){
int u = G[v][i] ;
for(int j = cnt ; j >= 0 ; j --){
for(int k = 0 ; k <= j ; k ++){
if(dp[v][j] > dp[v][j - k] + dp[u][k]){
dp[v][j] = dp[v][j - k] + dp[u][k] ;
}
}
}
}
for(int i = 0 ; i <= cnt ; i ++){
dp[v][i] = (dp[v][i] > val[v]) ? val[v] : dp[v][i] ;
}
return cnt ;
}
void solve(){
val[0] = INF ;
for(int i = 1 ; i <= n ; i ++){
if(num[i] == 0)
G[0].push_back(i) ;
}
dfs(0) ;
int ans = INF ;
for(int i = m ; i <= n ; i ++){
ans = ans < dp[0][i] ? ans : dp[0][i] ;
}
printf("%d\n" , ans) ;
}
int main(){
while(read()){
solve() ;
}
return 0 ;
}