【分组背包问题 (HDU 3535 )】

用到至少选择一个,所以没有空间优化
分组背包问题:
常见的三种分组问题:
分成K组:
1、每组最多只能取一件物品
一维数组伪码:
for 0 to K  对每一组进行
    for W to 0   对每一个代价进行判断 ///1
     for all item i in group k        ///2 这行个互换好像也对
     dp[w]=max(dp[w],dp[w-c[i]]+v[i];   每个重量保证的只有一件物品来取最大值
2、每组随意取(为01背包问题)******摘抄网络**既然上面的顺序是限制每组最多取一个,那调换一下顺序即可,其实就是01背包。******
一维伪码:
for 0 t0 K
    for all item i in group k
      for W to 0
      dp[w]=max(dp[w],dp[w-c[i]]+v[i]);
3、每组至少取一个
没见过一维的伪代码
用二维:
dp[ki][j]表示当前组的一件物品不选
dp[ki-1][j-w[i]]+v[i] 表示这是在ki组选第一个
dp[ki][j-w[i]]+v[i] 表示在这个ki组中再次选一个
dp[ki][j](处理完后的值)=max(dp[ki][j],dp[ki-1][j-w[i]]+v[i],dp[ki][j-w[i]]+v[i]) max分开的时候要注意顺序 max(dp[ki][j],dp[ki-1][j-w[i]]+v[i])......
在初始化时是ki==0(没有组)这时是dp[0][j]=0 其余的是-inf ******解决一件物品都不取的问题

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define X 10005
#define inf 0x3f3f3f3f
using namespace std;
int main()
{
    int n,t;
    int m,s;
    cin>>n>>t;
    int dp[105][105];
    int  c[105],g[105];
    memset(dp,-inf,sizeof(dp));
    memset(dp[0],0,sizeof(dp[0]));
    for(int i=1;i<=n;++i)//k组
    {
        cin>>m>>s;
        for(int j=0;j<m;++j)
        {
            scanf("%d%d",&c[j],&g[j]);
        }
            if(s==0)
            {
            // for(int j=0;j<=t;++j)
              //  dp[i][j]=-1000000;
            for(int j=0;j<m;++j)
                for(int p=t;p>=c[j];--p)
            {
                dp[i][p]=max(dp[i][p],dp[i][p-c[j]]+g[j]);
                dp[i][p]=max(dp[i][p],dp[i-1][p-c[j]]+g[j]);

            }
           }
          else if(s==1)
           {
            for(int j=0;j<=t;++j)
              {
                  dp[i][j]=dp[i-1][j];//当前i个组继承前i-1个组
              }
                for(int j=0;j<m;++j)
                {
                    for(int p=t;p>=c[j];--p)
                    {
                        dp[i][p]=max(dp[i][p],dp[i-1][p-c[j]]+g[j]);
                    }
                }

           }
        else if(s==2)
        {
            for(int j=0;j<=t;++j)
                {
                    dp[i][j]=dp[i-1][j];
                }
             for(int j=0;j<m;++j)
            {
                for(int p=t;p>=c[j];--p)
                {
                   // dp[i][p]=max(dp[i][p],dp[i-1][p]);//不取
                    dp[i][p]=max(dp[i][p],dp[i][p-c[j]]+g[j]);//多个
                    //dp[i][p]=max(dp[i][p],dp[i-1][p-c[j]]+g[j]);//一个

                }
            }
        }
    }
   // if(dp[n][t]<0)
  //      cout<<-1<<endl;
  //  else
        cout<<max(dp[n][t],-1)<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值