N項目Vとバックパックの容量、[I]は、Vの値は、[I]は、項目を複数のグループに分割され、競合アイテムの各グループが、最もから選択されるWのi番目の商品の重量があります。 1は、
バックパックにアイテムがバックパックは、最も値を取得させることができるものを尋ねました
項目のそれぞれのグループを一度に処理することができるため項目のグループごとに、それは、01ナップザック問題として見ることができます。
入力フォーマット:
最初のライン:三つの整数、V(バックパックの容量、V <= 200)、N ( アイテムの数、N <= 30)およびT(最大グループ数、T <= 10)、
第2 ... N +行1:Wiは、Viは、pは、重み値を表す3つの整数各行は、各項目のグループ番号に属します。参照され、このブログのアイデアの形の二次元アレイのパフォーマンスの場合:
- グループサイクルの数
- 項目を選択
- ボリューム・サイクル
// 二维数组:
f[k][j]表示前k组体积为j的最大价值
for(int k=1; k<=T; ++k) //组别
for(int i=1; i<=N; ++i) //物品
for(int j=V; j>=0; j--) //体积
f[k][j] = max(f[k][j], v[k][i]+f[k-1][j-w[k][i]] ); //求组这组最大
ここで、f[k-1][j]
最大値jボリュームグループの前にK-1を参照すると、したがってv[k][i] + f[k-1][j-w[k][i]]
手段:I + K-1物品ボリュームグループJW [K] [I](左ボタンの体積にする前に、現在のセットを取ります商品のボリュームの現在の値から)値。
1次元の言葉に:
- パケットグループの数
- ボリューム・サイクル
- 商品のトラバーサル
// 一维数组 :f[j]表示体积为j的时候的最大价值!(每组都共用一个dp数组,dp数组保存最大价值)
for(int k=1; k<=T;k++)
for(int j=V; j>=0; j--) //分组体积
for(int i=1; i<=a[k][0]; i++){ //对体积里的每个物品
int x = a[k][i]; //x来记录物品编号
if(j>=w[i]) //容量大于第i个物品的体积
f[j] = max(f[j], v[x]+f[j-w[x]] ); //价值为
}
このうち、以下の一般的な1次元配列の形をとりました。
コードと入力値を参照することができ、このブログ
#include<iostream>
#include<algorithm>
#include <vector>
#include<cstring>
using namespace std;
const int maxn=105;
const int maxv=105;
const int maxt=15;
int N,V,T;
int v[maxn], w[maxn];
int dp[maxv]; //f存的是代价函数,因此以v为单位,f的意思是容量为c时该组取所需元素的最大值
int groupitem[maxt][maxn]; //a存放的是分组t里的物品编号
int main(){
cin>>V>>N>>T;
memset(&groupitem, 0, sizeof(groupitem)); //这一步似乎可有可无
// 输入
for(int i=1; i<=N; ++i){
int p;
cin>>w[i]>>v[i]>>p;
groupitem[p][++groupitem[p][0]] = i; //groupitem[p][0]来存放该组的数量
}
// 开始求解,分别是①对组;②对每组来说的容量;③对该组内的物品进行~
for(int i=1; i<=T; ++i){
for(int j=V; j>=0; --j)
for(int k=1; k<=groupitem[i][0]; k++){
int x = groupitem[i][k]; // 获取当前组的物品编号
//记得if语句判断一下:
if( j>=w[x] )
dp[j] = max(dp[j], v[x] + dp[j-w[x]]); //一维的写法, 关键是f[j-w[x]]去掉
}
}
cout<<dp[V]<<endl; //从而输出:容量为j的时候
return 0;
}