A : 01背包
题目描述
有 N 件物品和一个容量为 V 的背包。第 i 件物品的重量是 w[i],价值是 c[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
输入描述
第一行为 N(1≤N≤5000),V(1≤V≤5000)。
下面 N 行,第 i 行描述第 i 个物品的 w[i](1≤w[i]≤103),c[i](1≤c[i]≤103),用一个空格分隔。
输出描述
输出只有一个数,最大总价值。
测试样例
样例 1
输入:
10 9
7 1
8 10
7 10
7 7
7 6
3 7
4 1
3 3
9 1
1 4
输出:
14
解答
#include<bits/stdc++.h>
using namespace std;
int main(){
int N, V;
cin >> N >> V;
int w[N+1], c[N+1];
for (int i = 1; i <= N;i++){
cin >> w[i] >> c[i];
}
int f[N+1][V+1];
for (int i = 0; i <= N;i++){
for (int j = 0; j <= V;j++){
f[i][j] = 0;
}
}
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= V;j++)
if(j>=w[i])
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + c[i]);
else
f[i][j] = f[i - 1][j];
}
cout << f[N][V] << endl;
return 0;
}
B : 完全背包
题目描述
有 N 种物品(每种有无限多个)和一个容量为 V 的背包。第 i 种物品的重量是 w[i],价值是 c[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
输入描述
第一行为 N(1≤N≤5000),V(1≤V≤5000)。
下面 N 行,第 i 行描述第 i 种物品的 w[i](1≤w[i]≤103),c[i](1≤c[i]≤103),用一个空格分隔。
输出描述
输出只有一个数,最大总价值。
测试样例
样例 1
输入:
10 8
4 5
1 1
1 5
5 4
5 10
6 5
1 1
5 6
7 4
4 5
输出:
40
解答
#include<bits/stdc++.h>
using namespace std;
int main(){
int N, V;
cin >> N >> V;
int w[N+1], c[N+1];
for (int i = 1; i <= N;i++){
cin >> w[i] >> c[i];
}
int f[N+1][V+1];
int x = 0;
for (int i = 0; i <= N;i++){
for (int j = 0; j <= V;j++){
f[i][j] = 0;
}
}
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= V;j++){
int y = 0;
for (int k = 1; k <= V / w[i];k++){
if(j>=k*w[i]){
x = f[i - 1][j - k * w[i]] + k*c[i];
y = max(x, y);
}
}
int s = f[i - 1][j];
f[i][j] = max(y, s);
}
}
cout << f[N][V] << endl;
return 0;
}
C : 多重背包
多重背包
题目描述
有 N 种物品和一个容量为 V 的背包。第 i 种物品的重量是 w[i],价值是 c[i],有 k[i]个。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
输入描述
第一行为 N(1≤N≤104),V(1≤V≤104)。
下面 N 行,第 i 行描述第 i 种物品的 w[i](1≤w[i]≤102),c[i](1≤c[i]≤106),k[i](1≤k[i]≤102),用一个空格分隔。
输出描述
输出只有一个数,最大总价值。
测试样例
样例 1
输入:
6 1
7 10 4
6 9 1
6 8 1
10 6 2
9 8 3
1 3 2
输出:
3
解答
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll tot;
ll N, V;
ll w[1000000],v[1000000];
void addItem(ll x, ll y){
w[tot] = x;
v[tot] = y;
tot++;
}
void init(){
tot = 1;
}
int main(){
cin >> N >> V;
// ll c[N+1],g[N+2];
init();
ll weight, value, count;
for (int i = 1; i <= N;i++){
cin >> weight >> value >> count;
for (int i = 1; i <= count; i *= 2){
addItem(weight * i, value * i);
count -= i;
}
if(count>0){
addItem(weight * count, value * count);
}
}
ll f[2][V+1];
for (int i = 0; i < 2;i++){
for (int j = 0; j <= V;j++){
f[i][j] = 0;
}
}
for (int i = 1; i < tot; i++)
{
for (int j = 1; j <= V; j++)
{
f[i & 1][j] = f[(i - 1) & 1][j];
if (j >= w[i])
{
f[i & 1][j] = max(f[(i - 1) & 1][j], f[(i - 1) & 1][j - w[i]] + v[i]);
}
}
}
cout << f[(tot - 1) & 1][V]<<endl;
return 0;
}
D : 分组背包
分组背包
题目描述
有 N 件物品和一个容量为 V 的背包,将所有的物品划分成若干组,每个组里面的物品最多选一件。第 i 件物品的重量是 w[i],价值是 c[i],属于组 k[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
输入描述
第一行为 N(1≤N≤103),V(1≤V≤103)。
下面 N 行,第 i 行描述第 i 个物品的 w[i](1≤w[i]≤102),c[i](1≤c[i]≤106),k[i](1≤k[i]≤102),用一个空格分隔。
输出描述
输出只有一个数,最大总价值。
测试样例
样例 1
输入:
7 9
6 6 3
5 10 3
3 5 1
9 4 4
6 1 4
8 3 5
5 2 2
输出:
15
解答
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll N, V;
ll w[1000000], v[10000010];
ll tot;
// vector<ll> group;
ll group[101][1001];
ll a[101]; // 记录每一维group的最后一位
void init(){
for (int i = 0; i <= N;i++){
w[i] = 0;
v[i] = 0;
// groups[i].k = 0;/??//
}
tot = 0;
for (int i = 0; i <= 100;i++){
for (int j = 0; j <= 1000;j++){
group[i][j] = 0;
}
}
for (int i = 1; i <= 100;i++){
a[i] = 1;
}
}
int main(){
cin >> N >> V;
int x, y, z;
init();
for (int i = 1; i <= N;i++){
cin >> x >> y >> z;
w[i] = x;
v[i] = y;
if(group[z][1]==0){
tot++;
}
group[z][a[z]] = i;
a[z]++;
}
ll f[V + 1];
for (int i = 0; i <= V;i++){
f[i] = 0;
}
for (int i = 1; i <= 100; i++)
{
for (int j = V; j >= 1; j--)
{
for (int k : group[i])
{
if (j >= w[k])
{
f[j] = max(f[j], f[j - w[k]] + v[k]);
}
}
}
}
cout << f[V] << endl;
return 0;
}
E : 超大背包
题目描述
有 N 件物品和一个容量为 V 的背包。第 i 件物品的重量是 w[i],价值是 c[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
输入描述
第一行为 N(1≤N≤40),V(1≤V≤1015)。
下面 N 行,第 i 行描述第 i 个物品的 w[i](1≤w[i]≤1015),c[i](1≤c[i]≤1015),用一个空格分隔。
输出描述
输出只有一个数,最大总价值。
测试样例
样例 1
输入:
3 225274242
70498827 830583485
72910089 759360759
80945586 1095298545
输出:
2685242789
样例 2
输入:
27 1405406868
500580317 1559925714
1191095816 2052289019
2086671060 125049457
1467200227 1826963529
1054830291 1055178046
457445390 293196664
1428828824 1163887408
27108927 353186119
354284919 1641947343
1044113045 1319050872
814300917 42212882
802287458 2142953934
1178508095 943859578
2133693898 163905627
1687820729 1091482274
737249638 2121489517
1203304272 1081378899
581034126 832395967
1370524005 487337507
178833685 1328104836
512934928 897959032
1629846549 1677014752
2011536830 64430283
547991487 1683026867
2125422226 728351378
744805340 261154211
1909716650 317131682
输出:
5466192232
解答
#include <iostream>
#include <cmath>
#include <algorithm>
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int Max = 42;
typedef long long ll;
ll w[Max], v[Max];
ll N, W;
pair<ll, ll> arr[1 << (Max / 2)]; //重量,价值
pair<ll, ll> arr2[1 << (Max / 2)]; //重量,价值
pair<ll, ll> temp[1 << Max / 2];
ll ans = 0;
bool cmp(pair<ll, ll>& a, pair<ll, ll>& b)
{
return a.second < b.second;
}
void solve()
{
ll n = N / 2;
for (ll i = 0; i < (1 << n); i++)
{
ll now_w = 0, now_v = 0;
for (int j = 0; j < n; j++)
{
if (i >> j & 1) //对于二进制数i,它的第j位是1
{
now_w += w[j];
now_v += v[j];
}
}
arr[i].first = now_w; //二进制数i表示当前选中的状态,对这个状态来计算当前的价值和重量
arr[i].second = now_v;
}
sort(arr, arr + (1 << n)); //第一维升序
ll current_min = arr[0].second;
ll j = 0;
// 进行部分数据剔除
for (ll i = 1; i < pow(2, n); i++)
{
if (arr[i].second > current_min)
arr2[j++] = arr[i];
else
current_min = arr[i].second;
}
// 第二部分的选择,同时进行判断最大的值
for (ll i = 0; i < (1 << (N - n)); i++)
{
ll now_w = 0, now_v = 0;
for (ll k = 0; k < (N - n); k++)
{
if ((i >> k) & 1)
{
now_w += w[n + k];
now_v += v[n + k];
}
}
if (now_w <= W)
{
ll v = 0;
for (ll s = j - 1; s >= 0; s--)
{
if (arr2[s].first <= W - now_w) //在符合重量要求的前提下找最大重量
{
for (int p = 0; p <= s; p++)
temp[p] = arr2[p];
sort(temp, temp + s + 1, cmp);
v = temp[s].second;
break;
}
}
//cout << "v = " << v << endl;
ans = max(ans, v + now_v);
}
}
}
int main()
{
cin >> N >> W;
for (ll i = 0; i < N; i++)
cin >> w[i] >> v[i];
solve();
cout << ans << endl;
return 0;
}