分组背包

题目描述

一个旅行者有一个最多能用$V$公斤的背包,现在有$n$件物品,它们的重量分别是$W_1,W_2,...,W_n$,它们的价值分别为$C_1,C_2,...,C_n$。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

输入格式

   第$1$行:三个整数,$V$(背包容量,$V\leqslant 200$),$N$(物品数量,$N\leqslant 30$)和$T$(最大组号,$T\leqslant 10$);

   第$2..N+1$行:每行三个整数$W_i,C_i,P$,表示每个物品的重量,价值,所属组号。

输出格式

 仅一行,一个数,表示最大总价值。

样例数据

输入

10 6 3

2  1  1

3  3  1

4  8  2

6  9  2

2  8  3

3  9  3

输出

20

分析

首先判断一个分组当中的一件物品,同01背包一样,此物品存在两种状态,取与不取,若取此物品,则继续判断下一组的第一件物品,若不取此物品,则继续判断本组下一件物品,若该物品为本组最后一件物品,则判断下一组。也就是说设$Dp_{k,v}$表示前$k$组物品花费费用$v$能取得的最大权值,则有:$Dp_{k,v}=max\left \{Dp_{k-1,v}+Dp_{k-1,v-Weight_i}\right \}$,其中物品$i$属于组$k$。

一维优化的状态转移方程:

代码

#include <bits/stdc++.h>

#define Enter puts("")
#define Space putchar(' ')
#define MAXN 1001

using namespace std;

typedef long long ll;
typedef double Db;

inline ll Read()
{
    ll Ans = 0;
    char Ch = getchar() , Las = ' ';
    while(!isdigit(Ch))
    {
        Las = Ch;
        Ch = getchar();
    }
    while(isdigit(Ch))
    {
        Ans = (Ans << 3) + (Ans << 1) + Ch - '0';
        Ch = getchar();
    }
    if(Las == '-')
        Ans = -Ans;
    return Ans;
}

inline void Write(ll x)
{
    if(x < 0)
    {
        x = -x;
        putchar('-');
    }
    if(x >= 10)
        Write(x / 10);
    putchar(x % 10 + '0');
}

int Weight[MAXN] , Value[MAXN];
int Dp[MAXN];
vector <int> Vector[MAXN];

int main()
{
    int V = Read() , N = Read() , T = Read();
    int P;
    for(int i = 1; i <= N; i++)
    {
        Weight[i] = Read() , Value[i] = Read() , P = Read();
        Vector[P].push_back(i);
    }
    for(int i = 1; i <= T; i++)
        for(int j = V; j >= 0; j--)
            for(int k = 0; k < Vector[i].size(); k++)
            {
                int Temp = Vector[i][k];
                if(j >= Weight[Temp])
                    Dp[j] = max(Dp[j] , Dp[j - Weight[Temp]] + Value[Temp]);    
            }
    Write(Dp[V]);
    return 0;
}

/*
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
*/

 

posted @ 2021-05-25 20:10  Tenderfoot  阅读(71)  评论(0编辑  收藏  举报