动态规划基本分析方法

  1. 状态表示 f (i,j)
  • 集合
    • 所有选法
    • 条件
      • 只从前i个物品中选
      • 总体积 <= j
  • 属性
    • Max
    • Min
    • 数量
  1. 状态计算 (集合划分)

01背包(每个物品在只能用一次)

01bag

二维表示

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
32
33
34
35
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
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 - 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
28
29
30
31
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
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 = m ; j >= v[i] ; j--)
{
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}

cout << f[m] << endl;

return 0;
}

完全背包(一个物品可以选取无限次)

物品不再是只有1个,而是有无数个

wanquan

朴素做法

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
32
33
34
#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1010;

int n, m;
int v[N], w[N];
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 - v[i] * k] + w[i] * k);
}
}
}

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
29
30
31
32
33
34
#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1010;

int n, m;
int v[N], w[N];
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 - v[i] * k] + w[i] * k);
}
}
}

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
29
30
31
#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1010;

int n, m;
int v[N], w[N];
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;

}