题解 P1899 【魔法物品】

· · 题解

//又是一个好(nan)题好(nan)题 
//首先,普通物品一开始就卖掉就可以,因为它不会增值
//至于魔法物品
//如果一个魔法物品使用了卷轴后的价值减去买卷轴的钱还不如鉴定前的价值高,那么我们鉴定这个魔法物品是要亏本的
//这样的魔法物品我们把它称为假的魔法物品,当成普通物品处理就好 
//否则如果鉴定之后可以赚钱,就把它称之为真的魔法物品 

//后边怎么体现买了卷轴的时候有点绕,其实看看算魔法药品利润的那个式子就很好理解了 

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<sstream>
using namespace std;

const int N=1005;
const int M=1e7+5;

int n,P;
int allv,v;
//allv是所有魔法物品鉴定前和普通物品的价值的和, v是普通物品的价值和,是初始资金 
int dp[M];
//dp[i]表示通过卖魔法物品得到i元钱所赔的最小利润的和 
int mf,p1[N],profit[N];
//mf是真真的魔法物品的数量,p1是是鉴定前的价值,profit是鉴定后能获取的利润 

int main()
{
    string S;
    scanf("%d%d",&n,&P);
    getline(cin,S);     //一定要用getline读换行,不要用getchar() 
    for(int i=1;i<=n;++i)
    {
        stringstream s;     //字符串流黑科技,不懂的百度 
        getline(cin,S);     //读入这一行的内容 
        s<<S;   //将字符串S转化成一个流字符串 
        int a,b;
        s>>a;   //第一个价值 
        allv+=a; 
        if(s>>b&&b-P-a>0)   //如果这是个真的魔法物品  s>>b表示这一行还有第二个数字,b-P-a>0表示鉴定之后能获得利润 
        {
            ++mf;
            p1[mf]=a;   //鉴定前价值 
            profit[mf]=b-P-a;   //鉴定后价值 
        }
        else    //假的魔法物品,当成普通物品处理 
            v+=a;
    }
//  cout<<allv<<" "<<v;
    if(v<P) //手中卖掉普通物品后的初始资金不够买卷轴 
    {
        for(int i=1;i<=allv-v;++i)  //卖掉鉴定前的真的魔法物品最多可以获得allv-v元钱 
            dp[i]=999999999;
        for(int i=1;i<=mf;++i)      //枚举魔法物品个数 
        {
            for(int j=allv-v;j>=p1[i];--j)  //卖魔法药品得到j元钱要损失多少利益 
            {
                dp[j]=min(dp[j],dp[j-p1[i]]+profit[i]);     //求最少损失 
            }
        }
        int minn=999999999;
        for(int i=P-v;i<=allv-v;++i)    //找最小损失    i=P-v是因为我们最少需要P-v元钱就可以买卷轴 
            minn=min(minn,dp[i]);
        if(minn==999999999)     //卖完所有的魔法药品仍然买不了卷轴,那么只能全部按鉴定前价格出售 
            printf("%d",allv);
        else    //能买卷轴了 
        {
            for(int i=1;i<=mf;++i)  //加上鉴定后能获得的的利润 
                allv+=profit[i];
            printf("%d",allv-minn);     //要减掉卖魔法物品的利润损失 
        }
    }
    else    //不卖魔法药品就能买卷轴 
    {
        for(int i=1;i<=mf;++i)  //加上利润 
            allv+=profit[i];
        printf("%d",allv);
    }
    return 0;
}