HDU - 3535 AreYouBusy

这是一个关于动态规划的题目,目标是根据物品集合的类型(0, 1, 2)和背包容量,求解最大价值。类型0的集合必须至少选一个物品,类型1的集合最多选一个,类型2的集合可以自由选择。通过定义dp矩阵,根据集合类型更新状态转移方程,最终得到最大价值。" 117773141,10295069,解决YY语音麦克风无声及噪音问题指南,"['YY直播助手', '麦克风设置', '声卡驱动', '手机语音', '网络连接']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AreYouBusy
题意:给你n个物品的集合,每个物品的集合有m个物品,以及该集合的类型s,每个物品都有val和cost属性,如果集合的类型属于0,则该集合的物品至少选一个,如果集合类型属于1,则该集合最多选择一个物品,如果该集合类型属于2,那么该集合的物品可以任选。
现在小明的背包的容量为t,求最大的val值。

数据范围:
1 &lt; = n , t &lt; = 100 1&lt;=n,t&lt;=100 1<=n,t<=100
0 &lt; = v a l , c o s t &lt; = 100 0&lt;=val,cost&lt;=100 0<=val,cost<=100
s = 1 , 2 , 3 s = 1,2,3 s=1,2,3
1 &lt; = m &lt; = 100 1&lt;=m&lt;=100 1<=m<=100
输入样例:

3 3
2 1
2 5
3 8
2 0
1 0
2 1
3 2
4 3
2 1
1 1

3 4
2 1
2 5
3 8
2 0
1 1
2 8
3 2
4 4
2 1
1 1

1 1
1 0
2 1

5 3
2 0
1 0
2 1
2 0
2 2
1 1
2 0
3 2
2 1
2 1
1 5
2 8
3 2
3 8
4 9
5 10

输出样例:

5
13
-1
-1

思 路:首先定义 d p [ i ] [ j ] dp[i][j] dp[i][j],到第i个集合容量为j时的最大价值。对于当前集合i类型为0时,至少选择一个,可以初始化 d p [ i ] [ 0 − t ] = − I N F dp[i][0-t] = -INF dp[i][0t]=INF,这样就变成一个0,1背包了,状态转移方程为: d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i ] [ j − c o s t [ i ] ] + v a l [ i ] ) ; d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j − c o s t [ i ] ] + v a l [ i ] ) ; dp[i][j] = max(dp[i][j],dp[i][j-cost[i]]+val[i]);dp[i][j] = max(dp[i][j],dp[i-1][j-cost[i]]+val[i]); dp[i][j]=max(dp[i][j],dp[i][jcost[i]]+val[i]);dp[i][j]=max(dp[i][j],dp[i1][jcost[i]]+val[i]);两者位置不可以变化,否则可能当cost[i] = 0时,这个包可能会多次选择。对于当前集合i类型为1时,最多选择一个,那么当前集合的状态只能有上一个集合的状态转移过来。 d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j − c o s t [ i ] ] + v a l [ i ] ) dp[i][j] = max(dp[i][j],dp[i-1][j-cost[i]]+val[i]) dp[i][j]=max(dp[i][j],dp[i1][jcost[i]]+val[i])
如果当前集合的类型是3的话那么就是一个简单的0,1背包了。和状态为0的不同就是可以不选。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4+5;
int dp[100+5][maxn];
int val[100+5],cost[100+5];
int n,t;
int m,s;
int main(){
    //freopen("input.txt","r",stdin);
    while(~scanf("%d %d",&n,&t)){
        memset(dp,0,sizeof(dp));
        for(int pp=1;pp<=n;pp++){
            scanf("%d %d",&m,&s);
            for(int i=1;i<=m;i++){
                scanf("%d %d",&cost[i],&val[i]);
            }
            if(s == 0){ //至少选一个
                for(int i=0;i<=t;i++)dp[pp][i] = -INF;
                for(int i=1;i<=m;i++){
                    for(int j=t;j>=cost[i];j--){
                        dp[pp][j] = max(dp[pp][j],dp[pp][j-cost[i]]+val[i]);  //这个顺序不能换哈
                        dp[pp][j] = max(dp[pp][j],dp[pp-1][j-cost[i]]+val[i]);
                    }
                }
            }else if(s == 1){ //最多选一个
                for(int i=0;i<=t;i++) dp[pp][i] = dp[pp-1][i];
                for(int i=1;i<=m;i++){
                    for(int j=t;j>=cost[i];j--){
                        dp[pp][j] = max(dp[pp][j],dp[pp-1][j-cost[i]]+val[i]);
                    }
                }
            }else if(s == 2){ //随意选不选
                for(int i=0;i<=t;i++)dp[pp][i] = dp[pp-1][i];
                for(int i=1;i<=m;i++){
                    for(int j=t;j>=cost[i];j--){
                        dp[pp][j] = max(dp[pp][j],dp[pp][j-cost[i]]+val[i]);
                        dp[pp][j] = max(dp[pp][j],dp[pp-1][j-cost[i]]+val[i]);
                    }
                }
            }
        }
        dp[n][t] = max(dp[n][t],-1);
        printf("%d\n",dp[n][t]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值