• ZOJ3164【背包问题(好题)】


    %%%%%%%%%%%%%%%岐爷

    这一发从来没写过这么旺盛的背包问题。。。

    想法很多,但是好难执行。

    题意:
    有N种饼干,1-N
    每种最多想买Ki个,ki等于0的话没有上界
    对于第i种饼干的权值是Ei
    第i种饼干的价格Pi
    有D钱。

    还有G组

    每组只能选一种。

    思路:
    有两种背包,一种是在一定的组里,还有没有特定关系;
    没有特定关系的,如果没有限定数或者限定数*花费大于总费用,直接完全背包;否则就是二进制优化的0/1背包;
    有特定关系的就是一个分组背包,先预处理第i组j花费下的最优情况,且初始化每组每个花费下的价值都是-INF,然后最后dp,之前还要预处理一种物品在j花费下所能达到的最优值;
    最后dp将每一个分组的价格当做一次01背包 ,最里面再for一层。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e3+50;
    const int INF=0x3f3f3f3f;
    int n,W;
    
    void zero_one(int dp[],int w,int val)
    {
        for(int i=W;i>=w;i--)
            if(dp[i-w]>-INF)
                dp[i]=max(dp[i],dp[i-w]+val);
    }
    
    void compelet(int dp[],int w,int val)
    {
        for(int i=w;i<=W;i++)
            if(dp[i-w]>-INF)
                dp[i]=max(dp[i],dp[i-w]+val);
    }
    
    void init(int dp[])
    {
        fill(dp,dp+W+1,-INF);
        dp[0]=0;
    }
    
    int Kkk[N],Eee[N],Ppp[N];
    int mp[N];
    int dp[N],temp[N];
    char s[N];
    int w[10][N];
    
    int main()
    {
        while(~scanf("%d%d",&n,&W))
        {
            for(int i=1; i<=n; i++)
                scanf("%d%d%d",&Kkk[i],&Eee[i],&Ppp[i]);
            int G,len;
            scanf("%d",&G);
            getchar();
            memset(mp,0,sizeof(mp));
            for(int i=1; i<=G; i++)
            {
                gets(s);
                len=strlen(s);
                for(int j=0; j<len;)
                {
                    if(s[j]>='1'&&s[j]<='9')
                    {
                        int sum=0;
                        while(s[j]>='0' && s[j] <= '9')
                        {
                            sum=sum*10+s[j]-'0';
                            j++;
                        }
                        mp[sum]=i;
                    }
                    else
                        j++;
                }
            }
    
            int k,ww,ept;
            
            init(dp);
            for(int i=1;i<=G;i++)
                init(w[i]);
            
            for(int i=1; i<=n; i++)
            {
                if(mp[i])
                    init(temp);
                if(!Kkk[i]||Kkk[i]*Ppp[i]>=W)
                {
                    compelet(mp[i]?temp:dp,Ppp[i],Eee[i]);
                }
                else
                {
                    k=1;
                    while(k<=Kkk[i])
                    {
                        ww=k*Ppp[i];
                        ept=k*Eee[i];
                        zero_one(mp[i]?temp:dp,ww,ept);
                        Kkk[i]-=k;
                        k<<=1;
                    }
                    ww=Kkk[i]*Ppp[i];
                    ept=Kkk[i]*Eee[i];
                    zero_one(mp[i]?temp:dp,ww,ept);
                }
                if(mp[i])
                    for(int j=0;j<=W;j++)
                        w[mp[i]][j]=max(w[mp[i]][j],temp[j]); //预处理ww代表某一组里占花费j的最大收获
            }
    
            for(int i=1;i<=G;i++)
                for(int j=W;j>=0;j--)
                    for(int k=0;k<=j;k++)
                            if(dp[j-k]>-INF&&w[i][k]>-INF)
                                dp[j]=max(dp[j],dp[j-k]+w[i][k]);
    
            if(dp[W]>=0)
                printf("%d
    ",dp[W]);
            else
                puts("i'm sorry...");
            puts("");
        }
        return 0;
    }
    
    /*
    2 1024
    0 1 3
    0 0 1
    0
    
    10 1023
    1 1 1
    1 1 2
    1 1 4
    1 1 8
    1 1 16
    1 1 32
    1 1 64
    1 1 128
    3 -1 256
    1 1 512
    1
    9 10
    
    10 1023
    1 1 1
    1 1 2
    1 1 4
    1 1 8
    1 1 16
    1 1 32
    1 1 64
    1 1 128
    1 1 256
    1 1 512
    1
    9 10
    */
    


  • 相关阅读:
    2016计算机专业考研:c++大学教程第二版目录(下)
    2016考研计算机考研备考书籍推荐
    2014年计算机考研真题重点选择题部分真题及解析
    2016计算机考研:数据结构常用算法精析
    2015考研计算机专业基础综合试题真题及答案(1)
    java串讲之String 如何定义字符串对象
    WindowsService
    sql 将datetime类型转化为指定格式的字符串
    C# 利用SMTP异步发送邮件
    Visual Studio
  • 原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777468.html
Copyright © 2020-2023  润新知