0%

01背包

有$n$个重量和价值分别为$w_{i}$, $v_{i}$的物品。从这些物品中挑选出总重量不超过$W$的物品,求所有挑选方案中价值总和的最大值

$1 \leq n \leq 100$

$1 \leq w_{i}, v_{i} \leq 100$

$1 \leq W \leq 10000$

$dp[i+1][j] := $ 从前$i$个物品中挑选出总重量不超过$j$的物品,所有挑选方案中价值总和的最大值.

$dp[i+1][j] = max(dp[i][j], dp[i][j-w[i]] + v[i])$

1
2
3
4
5
6
7
8
9
10
11
12
void solve(){
for(int i = 0; i < n; i++) //tip: i start from 0
for(int j = 0; j <= W; j++){ //tip: j can equal to W
if(j - w[i] >= 0) {
dp[i + 1][j] = max(dp[i][j], dp[i][j - w[i]], + v[i]);
}
else {
dp[i + 1][j] = d[i][j];
}
}
printf("%d\n", dp[n][W]);
}

$dp[i][j] :=$ 从第$i$个物品开始,挑选出总重量不超过$j$的物品,所有挑选方案中价值总和的最大值.

$dp[i][j] = max(dp[i+1][j], dp[i+1][j-w[i]] + v[i])$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
dp[MAX_N+1][MAX_W+1];
int N;
int solve(int i, int j){
int res;
if (dp[i][j] >= 0){
return dp[i][j];
}
if (i == n) {
res = 0;
}
if (j < w[i]) {
res = solve(i + 1, j);
}
else{
res = max(solve(i + 1, j), solve(i + 1, j - w[i]) + v[i]);
}
return dp[i][j] = res;
}

void main() {
memset(dp, -1, sizeof(dp));
printf("%d\n", solve(0, W));
}
1
2
3
4
5
6
7
for (int i = n - 1; i >=0; i--)
for(int j = 0; j <= W; j++) {
if(j - w[i] < 0)
dp[i][j] = dp[i + 1][j];
else
dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
}

此外,还可以把状态转移想象成从“前$i$个物品中选取总重量不超过$j$时的状态 ”向“前$i+1$个物品中选取总重量不超过$j$” 和“前$i + 1$个物品中选取总重量不超过$j + w[i]$时的状态”的转移

1
2
3
4
5
6
7
8
9
void solve() {
for (int i = 0; i < n; i++)
for (int j = 0; j <= W; j++) {
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]);
if (j + w[i] <= W) {
dp[i + 1][j + w[i]] = max(dp[i + 1][j + w[i]], dp[i][j] + v[i]);
}
}
}

最长公共子序列问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int n, m;
int dp[NAX_N][MAX_M];
char s[MAX_N], t[MAX_M];
void solve() {
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(s[i] == s[j])
dp[i + 1][j + 1] = dp[i][j] + 1;
else
dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);
}
}
printf("%d\n", dp[n][m]);
}

完全背包问题

$dp[i+1][j]:=$从前i+1个物品中挑选总重量不超过j时总价值的最大值。

$dp[0][j]=0$

$dp[i+1][j]=max(dp[i][j-kw[i]]+kv[i]) \ \ |\ (0 \leq k )$

1
2
3
4
5
6
7
8
9
10
11
12
int dp[MAX_N][MAX_M];

void solve() {
for(int i = 0; i < n; i++) {
for (int j = 0; j <= W; j++) {
for (int k = 0; k * w[i] <= j; k++) {
dp[i + 1][j] = max(dp[i][j], dp[i][j - k * w[i]] + k * v[i]);
}
}
}
printf("%d\n", dp[n][W]);
}

在$dp[i+1][j]$中选择$k(k\ \geq\ 1)$个的情况,与在$dp[i + 1][j - w[i]]$中选择k-1个的情况是相同的,所以$dp[i+1][j]$的递推种$k \geq 1$的部分已经在$dp[i+1][j-w[i]]$种计算完成了。

$dp[i+1][j]=max(dp[i][j-kw[i]]+kv[i]) \ \ |\ (0 \leq k )$

$=max(dp[i][j], max(dp[i][j-kw[i]]+kv[i]) \ \ |\ (1 \leq k ))$

$=max(dp[i][j], max(dp[i][(j-w[i])-kw[i]]+kv[i]\ \ |\ (0 \leq k ))+v[i] )$

$=max(dp[i][j], dp[i+1][j-w[i]]+v[i])$

我们从哪里来,又将到哪里去,生命有何意义,我们该如何认识自己?这本书充满想象力。任何生物,包括我们自己,都只是基因的生存工具。这本书是实实在在的认知科学,复制/变异/淘汰三种简单的机制可以演变出大千世界生命现象里的林林总总。
阅读全文 »

Happy Birthday!

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment