HDU - 3535 AreYouBusy

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37129433/article/details/82860570

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

数据范围:
1 < = n , t < = 100 1<=n,t<=100
0 < = v a l , c o s t < = 100 0<=val,cost<=100
s = 1 , 2 , 3 s = 1,2,3
1 < = m < = 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] ,到第i个集合容量为j时的最大价值。对于当前集合i类型为0时,至少选择一个,可以初始化 d p [ i ] [ 0 t ] = I N F dp[i][0-t] = -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]); 两者位置不可以变化,否则可能当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])
如果当前集合的类型是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;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/82860570
hdu
今日推荐