背包问题
2019-12-06 23:39:24
本文总阅读量

01背包问题

给定物品的数量n(每一种物品只有一件)以及每件物品的价值,一个容量为v的背包,问怎样装物品使总价值最大。

朴素算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 1010;

int v[N], w[N]; // v 代表体积 w 代表权重 y总写的和其他人正好反着。 其他人 w 代表weight v 代表 value
int f[N][N];
int n, m;

int main()
{
scanf("%d%d", &n, &m);

for (int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]);

for (int i = 1; i <= n; i++)
for (int j = 0; j <= m; j++)
{
f[i][j] = f[i - 1][j];
if (v[i] <= j) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}

cout << f[n][m] << endl;

return 0;
}
优化

优化之前先看一下滚动数组。使用滚动数组可以大大减少空间复杂度。

二维变一维,最终优化结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int v[N], w[N];
int n, m, f[N];

int main()
{
cin >> n >> m;

for (int i = 1; i <= n; i++)
cin >> v[i] >> w[i];

for (int i = 1; i <= n; i++)
for (int j = m; j >= v[i]; j--)
f[j] = max(f[j], f[j - v[i]] + w[i]);

cout << f[m] << endl;

return 0;
}

完全背包问题

给定n种物品(每一种物品有无限个)以及每一种物品的价值,一个容量为v的背包,问怎样装物品使价值最大。

朴素算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int v[N], w[N];
int n, m;
int f[N][N];

int main()
{
cin >> n >> m;

for (int i = 1; i <= n; i++)
cin >> v[i] >> w[i];

for (int i = 1; i <= n; i++)
for (int j = 0; j <= m; j++)
for (int k = 0; k * v[i] <= j; k++)
f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);

cout << f[n][m] << endl;

return 0;
}
优化
1
2
3
4
5
6
/*
* f[i][j] = max(f[i - 1][j], f[i - 1][j - v] + w, f[i - 1][j - 2v] + 2w, ....,f[i - 1][j - x * v] + x * w)
* f[i][j - v] = max( f[i - 1][j - v] , f[i - 1][j - 2v] + w, .....,f[i - 1][j - x * v] + (x - 1) * w)
*
* f[i][j] = max(f[i - 1][j], f[i][j - v] + w);
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int v[N], w[N];
int n, m;
int f[N][N];

int main()
{
cin >> n >> m;

for (int i = 1; i <= n; i++)
cin >> v[i] >> w[i];

for (int i = 1; i <= n; i++)
for (int j = 0; j <= m; j++)
{
f[i][j] = f[i - 1][j];
if (j >= v[i]) f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
}

cout << f[n][m] << endl;

return 0;
}
优化成一维
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int v[N], w[N];
int n, m;
int f[N];

int main()
{
cin >> n >> m;

for (int i = 1; i <= n; i++)
cin >> v[i] >> w[i];

for (int i = 1; i <= n; i++)
for (int j = v[i]; j <= m; j++)
f[j] = max(f[j], f[j - v[i]] + w[i]);

cout << f[m] << endl;

return 0;
}

多重背包问题

朴素算法