分组背包
题目描述
一个旅行者有一个最多能用$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 */