SWERC2017 Ingredients 拓扑排序+01背包(坑)

写在开头

    这是我的第一篇博文。写博客的目的仅为提醒自己知识点,便于梳理与回顾,多半以微薄之见胡言乱语,若错了欢迎指点。

 题意

   大厨要列一个展示菜单给米其林的视察员看。他想在预算为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[剩余费用]的最大声望值时的费用,即是答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值