//----------------------------------------------------------------------------- //解法: // 依存関係の制約に注意して、普通のKnapsack問題の擬多項式時間アルゴリズム。 // O( costMax * numItem ) 時間。 //----------------------------------------------------------------------------- #include #include #include #include #include using namespace std; // 依存関係のツリー構造 struct node { vector child; int cost; int happy; node() : child(), cost(0), happy(0) {} }; typedef map tree; // 解候補の集合 typedef map CostHappyTable; typedef map::iterator cht_it; // ツリーの各ノードを訪問 // invariant: \exist h. (0,h) \in tbl // invariant: tbl, sub は(Cost,Happiness) の狭義双単調増加列 void rec( tree& t, const string& item, int costMax, map& tbl ) { node& n = t[item]; // itemを買う場合に最適な CostHappyTable を計算 CostHappyTable sub; for(cht_it i=tbl.begin(); i!=tbl.end(); ++i) if( i->first+n.cost <= costMax ) sub[i->first+n.cost] = i->second+n.happy; for(int i=0; i!=n.child.size(); ++i) rec( t, n.child[i], costMax, sub ); // itemを買わない場合とマージ for(cht_it i=sub.begin(); i!=sub.end(); ++i) { // le <= i < ub cht_it ub = tbl.upper_bound( i->first ); cht_it le = ub; --le; // invariantを保ちつつ挿入 if( le->second < i->second ) { tbl[i->first] = i->second; while( ub != tbl.end() ) if( i->second >= ub->second ) { cht_it ub2=ub; ++ub; tbl.erase(ub2); } else break; } } } pair solve( tree& t, int cash ) { CostHappyTable tbl; tbl[0] = 0; rec( t, "&", cash, tbl ); return *tbl.rbegin(); } int main() { string name; int cash; while( cin>>name>>cash, name!="#" ) { assert( 0<=cash && cash<=1024 ); tree t; // 依存関係読み込み for(;;) { string item, dep; int cost, happiness; if( cin>>item, item=="%" ) break; cin >> dep >> cost >> happiness; assert( 0<=cost && cost<=1024 ); assert( 0<=happiness && happiness<=100000 ); t[dep].child.push_back(item); t[item].cost = cost; t[item].happy = happiness; } void validate( tree& t ); validate(t); // 解く pair ans = solve( t, cash ); // 出力 static bool is_first = true; if( is_first ) is_first=false; else cout<& ch = t[item].child; int Max = 0; for(int i=0; i!=ch.size(); ++i) { int a = 1+rec(t,ch[i]); Max = Max>a ? Max : a; } return Max; } }; for(tree::iterator it=t.begin(); it!=t.end(); ++it) assert( it->second.child.size() <= 32 ); assert( depth_checker::rec(t,"&") < 5 ); } /** // 遅い上に間違ってたぽい…? void aggregate( CostHappyTable& a, CostHappyTable& b, int cLimit ) { CostHappyTable g; for(cht_it it=a.begin(); it!=a.end(); ++it) for(cht_it jt=b.begin(); jt!=b.end(); ++jt) { int f = it->first + jt->first; int s = it->second + jt->second; if( f > cLimit ) break; else if( g[f] < s ) { g[f] = s; for(;;) { map::iterator kt = g.upper_bound(f); if( kt==g.end() || kt->second > s) break; g.erase(kt); } } } a = g; } void rec( tree& t, const string& item, int costMax, CostHappyTable& gt ) { gt.clear(); node& n = t[item]; if( costMax >= n.cost ) // このアイテムを買う場合 { gt[n.cost] = n.happy; for(int i=0; i!=n.child.size(); ++i) { CostHappyTable sub_gt; // 各childアイテムを最適に買ってみる rec( t, n.child[i], costMax-n.cost, sub_gt ); aggregate( gt, sub_gt, costMax ); // 集計 } } gt[0]; // 買わない場合 } **/