hdu3535AreYouBusy(分组背包问题)

31 篇文章 0 订阅
6 篇文章 0 订阅

常见的有三种,
一,每组最多取一个,
一维数组的伪代码
for 所有的组k
for v = V to 0
for 所有的i属于组k
f[v] = max{f[v], f[v -c[i]] + w[i]}
注意顺序不能写反,因为要限制每组最多取一个
二,每组任意取
既然上面的顺序是限制每组最多取一个,那调换一下顺序即可,其实就是01背包。
一维数组的伪代码
for 所有的组k
for 所有的i属于组k
for v = V to 0
f[v] = max{f[v], f[v -c[i]] + w[i]}
三,每组至少取一个
没见过一维的伪代码,
dp[ki}[i}表示当前不选,dp[ki-1}[i-b[ki}}+c[ki}表示这是第一个选,
dp[ki}[i-b[ki}}+c[ki}表示再在这一组中选。
初始化时记得ki==0,赋值0,
其他赋值-inf
dp[ki}[i}=max(dp[ki}[i},dp[ki-1}[i-b[ki}}+c[ki},dp[ki}[i-b[ki}}+c[ki})
//分开写时要注意顺序!!!

下面这道题是这三种的综合,由于第三种情况要用二维写,所以就都用二维写。

if(type==0) 
    for(int i=0;i<=T;i++) dp[ni][i]=-inf;
else
    for(int i=0;i<=T;i++) dp[ni][i]=dp[ni-1][i];

上面代码是将状态从上一个组传递到当前组。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int inf=0x7fffffff;
int dp[102][102];
int main(int argc, char const *argv[])
{
    int N,T;
    while(scanf("%d %d",&N,&T)==2){
        ms(dp);
        for(int ni=1;ni<=N;ni++)
        {
            int num,type;
            scanf("%d %d",&num,&type);
            if(type==0) for(int i=0;i<=T;i++) dp[ni][i]=-inf;
            else for(int i=0;i<=T;i++) dp[ni][i]=dp[ni-1][i];
            if(type==0){//至少选一个
                while(num--){
                    int c,g;
                    scanf("%d %d",&c,&g);
                    for(int i=T;i>=c;i--)
                    {
                        dp[ni][i]=max(dp[ni][i],dp[ni][i-c]+g);
                        dp[ni][i]=max(dp[ni][i],dp[ni-1][i-c]+g);
                    }
                }
            }
            else if(type==1){//至多选一个
                while(num--){
                    int c,g;
                    scanf("%d %d",&c,&g);
                    for(int i=T;i>=c;i--)
                    {
                        dp[ni][i]=max(dp[ni][i],dp[ni-1][i]);
                        dp[ni][i]=max(dp[ni][i],dp[ni-1][i-c]+g);
                    }
                }
            }
            else{//随意
                while(num--){
                    int c,g;
                    scanf("%d %d",&c,&g);
                    for(int i=T;i>=c;i--)
                    {
                        dp[ni][i]=max(dp[ni][i],dp[ni-1][i]);
                        dp[ni][i]=max(dp[ni][i],dp[ni][i-c]+g);
                        dp[ni][i]=max(dp[ni][i],dp[ni-1][i-c]+g);
                    }
                }
            }
        }
        if(dp[N][T]<0) puts("-1");
        else printf("%d\n",dp[N][T] );
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值