01-背包
f[0] = 0;
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]);
完全背包
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]);
多重背包
for(int i = 1; i <= n; i++)
for(int j = m; j >= v[i]; j--)
for(int k = 1; k <= s[i]; k++){ // s[i]第i个物品的数量
if(k * v[i] > j) break;
f[j] = max(f[j], f[j-k*v[i]] + k*w[i]);
}
分组背包
每组物品有若干个,同一组内的物品最多只能选一个。
for(int i = 0; i < n; i++){
int s;
cin >> s;
for(int j = 0; j < s; j++)
cin >> v[j] >> w[j];
for(int j = m; ~j; j--){
for(int k = 0; k < s; k++){
if(j < v[k]) break;
f[j] = max(f[j], f[j-v[k]] + w[k]);
}
}
}
数字三角形
// 最底层初始化
for(int i = 1; i <= n; i++)
f[n][i] = d[n][i];
// 从倒数第二层开始计算
for(int i = n-1; i >= 1; i--)
for(int j = 1; j <= i; j++)
f[i][j] = max(f[i+1][j], f[i+1][j+1]) + d[i][j];
最长上升子序列 LIS
f[0] = d[0];
for(int i = 1; i < n; i++)
f[i] = max(d[i], f[i-1] + d[i]);
// LIS
// f[i]:所有以第i个数结尾的上升子序列的最大值
for(int i = 0; i < n; i++){
f[i] = 1; // f[i]至少有a[i]这个数
for(int j = 0; j < n; j++){
if(a[i] >= a[j])
f[i] = max(f[i], f[j] + 1);
}
}
最长公共子序列 LCS
/*
f[i, j] 在字符串A的前i个字母中出现,且在字符串B的前j个字母中出现的子序列长度
若a[i] == b[j] f[i,j] = f[i-1, j-1] + 1
若a[i] != b[j] f[i,j] = max(f[i, j-1], f[i-1, j])
*/
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
if(a[i] == b[j]) f[i][j] = f[i-1][j-1] + 1;
else f[i][j] = max(f[i][j-1], f[i-1][j]);
}
最短编辑距离
int minDistance(string word1, string word2) {
int f[510][510];
f[0][0] = 0;
int n = word1.length(), m = word2.length();
// f[i][0] = f[i-1][0] + 1;
for(int i = 1; i <= n; i++) f[i][0] = i ;
for(int i = 1; i <= m; i++) f[0][i] = i;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
f[i][j] = min(f[i][j-1] + 1, f[i-1][j] + 1); // 删除和增加比较
if(word1[i-1] == word2[j-1]) f[i][j] = min(f[i][j], f[i-1][j-1]); // 如果相等,就不需要编辑
else f[i][j] = min(f[i][j], f[i-1][j-1] + 1);
}
}
return f[n][m];
}