写在开头
这是我的第一篇博文。写博客的目的仅为提醒自己知识点,便于梳理与回顾,多半以微薄之见胡言乱语,若错了欢迎指点。
题意
大厨要列一个展示菜单给米其林的视察员看。他想在预算为B元的情况下使自己的菜单价值最大。
输入:pizza派生款式,pizza基底 ,添加调料,调料价格,调料价值
若一款披萨先前么有出现过,说明它是基底,价格为0,价值为0
如果一款派生款式可以由多种加料顺序获得,那么优先选择价格最小的加料方式,价格相同的情况下选择价值最大的加料方式
同一款披萨只能出现一次
思路
做题时没想到是拓扑,直接边读入边更新,大佬学弟说是不对的,下为引用大佬学弟的话:“和最短路同理,给出的是一张图,它不会在更新一个点后更新后续结点,得到的价值和费用不是最优的。”实质上就是derive+base的组合,我没考虑更新一种derive变了之后在该行输入之前以它为底的pizza的价值。”
这道题目的关键在于得到每种派生款式的价格和价值,之后就是简单的01背包。
比赛时错误代码
#include<bits/stdc++.h> using namespace std; struct pizza { int cost; int pre; }; map<string,pizza> mp; string derive,base,ingre; const int N=1e6+10; int dp[N]; pizza food[N]; bool cmp(pizza a,pizza b) { if(a.pre==b.pre) return a.cost<b.cost; else return a.pre>b.cost; } int c,p; int main() { int V; cin>>V; int n; cin>>n; while(n--) { cin>>derive; cin>>base; cin>>ingre; cin>>c; cin>>p; // cout<<mp[derive].cost<<endl; // cout<<mp[base].cost<<endl; if(mp[derive].cost==0) { mp[derive].cost=mp[base].cost+c; mp[derive].pre=mp[base].pre+p; } else //derive已经有别的base可以得到 比较两种基下的价格和名声 { if(mp[base].cost+c<mp[derive].cost) { mp[derive].cost=mp[base].cost+c; mp[derive].pre=mp[base].pre+p; } else if(mp[base].cost+c==mp[derive].cost) { if(mp[base].pre+p>mp[derive].pre) { mp[derive].cost=mp[base].cost+c; mp[derive].pre=mp[base].pre+p; } } } } int cnt=0; for(map<string,pizza>::iterator it=mp.begin();it!=mp.end();++it) { //cout<<it->first<<' '<<(it->second).cost<<' '<<(it->second).pre<<endl; food[++cnt].cost=(it->second).cost; food[cnt].pre=(it->second).pre; } sort(food+1,food+cnt+1,cmp); // for(int i=1;i<=cnt;i++) // cout<<food[i].cost<<' '<<food[i].pre<<endl; for(int i=1;i<=cnt;i++) { for(int j=V;j>=food[i].cost;j--) { dp[j]=max(dp[j],dp[j-food[i].cost]+food[i].pre); } } // cout<<dp[V]<<endl; long long ans1=-1,ans2=0; for(int i=V;i>=0;i--) { if(ans1<=dp[i]) ans1=dp[i],ans2=i; } cout<<ans1<<endl; cout<<ans2<<endl; return 0; }
只想说一说01背包这里,一开始纠结如何输出最大声望值下的最小费用值,从耗费值为0(剩余费用为V)开始循环,记录最早出现的dp[剩余费用]的最大声望值时的费用,即是答案。