化零为整:状态表示:集合表示
化整为零:状态计算:分成子集
子集:
子集合划分依据:找最后一个不同点
状态表示:f(i, j)
状态定义:dp(i, j) :前i个物品,在体积为j时的最大价值
状态计算:满足不重复性
朴素代码
x
using namespace std;
int N, V;
int v[1002], w[1002];
int dp[1002][1002];
int main() {
cin >> N >> V;
for (int i = 1; i <= N; ++i) cin >> v[i] >> w[i];
for (int i = 1; i <= N; ++i) {
for (int j = 0; j <= V; ++j) {
// if (j >= v[i]) {
// dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
// } else {
// dp[i][j] = dp[i - 1][j];
// }
//优化1
dp[i][j] = dp[i - 1][j];
// 因为 dp[i][j] = dp[i - 1][j];
if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
}
}
cout << dp[N][V] << endl;
return 0;
}
优化
xxxxxxxxxx
using namespace std;
int N, V;
int v[1002], w[1002];
int dp[1002];
int main() {
cin >> N >> V;
for (int i = 1; i <= N; ++i) cin >> v[i] >> w[i];
for (int i = 1; i <= N; ++i) {
for (int j = V; ~j; --j) {
// if (j >= v[i]) {
// dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
// } else {
// dp[i][j] = dp[i - 1][j];
// }
//优化1
dp[j] = dp[j]; // 恒等于 dp[i][j] = dp[i - 1][j]; 因为:赋值的 是上一层的j
// 因为 dp[i][j] = dp[i - 1][j];
//下面一行代码 恒等于 dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
if (j >= v[i]) dp[j] = max(dp[j], dp[j - v[i]] + w[i]); //当j到过来,dp[j - v[i]]是i - 1层的,且未更新过,如果没有到过来,那么dp[j - v[i]]是i层的,且更新过的
}
}
cout << dp[V] << endl;
return 0;
}
using namespace std;
int N, V;
int v[1002], w[1002];
int dp[1002];
int main() {
cin >> N >> V;
for (int i = 1; i <= N; ++i) cin >> v[i] >> w[i];
for (int i = 1; i <= N; ++i) {
for (int j = V; j >= v[i]; --j) {
// if (j >= v[i]) {
// dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
// } else {
// dp[i][j] = dp[i - 1][j];
// }
//优化1
//dp[j] = dp[j]; // 恒等于 dp[i][j] = dp[i - 1][j]; 因为:赋值的 是上一层的j
// 因为 dp[i][j] = dp[i - 1][j];
//下面一行代码 恒等于 dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
dp[j] = max(dp[j], dp[j - v[i]] + w[i]); //dp[j - v[i]]是i - 1层的,且未更新过且
}
}
cout << dp[V] << endl;
return 0;
}
状态表示:f(i, j):前i个物品体积不超过j的最大值
状态计算:满足不重复性
集合划分:对于每个物品可以不限制的选择
那么dp(i, j) = max(dp(i - 1, j), dp(i - 1, j - vi) + wi, dp(i - 1, j - 2vi) + 2wi, ...),也就是dp(i, j) = max(集合0的值,集合1的值,集合2的值,...)
xxxxxxxxxx
/*
01: dp(i, j) = max(dp(i - 1, j), dp(i - 1, j - vi) + wi)
完全:dp(i, j) = max(dp(i - 1, j), dp(i, j - vi) + wi)
*/
using namespace std;
const int nn = 1005;
int N, V;
int dp[nn][nn];
int v[nn], w[nn];
int main() {
cin >> N >> V;
for (int i = 1; i <= N; ++i) cin >> v[i] >> w[i];
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= V; ++j) {
// if (j >= v[i]) dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i]);
// else dp[i][j] = dp[i - 1][j];
dp[i][j] = dp[i - 1][j];
if (j >= v[i]) dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i]);
}
}
cout << dp[N][V] << endl;
return 0;
}
xxxxxxxxxx
/*
01: dp(i, j) = max(dp(i - 1, j), dp(i - 1, j - vi) + wi)
完全:dp(i, j) = max(dp(i - 1, j), dp(i, j - vi) + wi)
*/
using namespace std;
const int nn = 1005;
int N, V;
// int dp[nn][nn];
int dp[nn];
int v[nn], w[nn];
int main() {
cin >> N >> V;
for (int i = 1; i <= N; ++i) cin >> v[i] >> w[i];
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= V; ++j) {
// if (j >= v[i]) dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i]);
// else dp[i][j] = dp[i - 1][j];
// dp[i][j] = dp[i - 1][j];
// if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i][j - v[i]] + w[i]);
dp[j] = dp[j];
if (j >= v[i]) dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
// cout << dp[N][V] << endl;
cout << dp[V] << endl;
return 0;
}
/*
01: dp(i, j) = max(dp(i - 1, j), dp(i - 1, j - vi) + wi)
完全:dp(i, j) = max(dp(i - 1, j), dp(i, j - vi) + wi)
*/
using namespace std;
const int nn = 1005;
int N, V;
// int dp[nn][nn];
int dp[nn];
int v[nn], w[nn];
int main() {
cin >> N >> V;
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 <= V; ++j) {
// if (j >= v[i]) dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i]);
// else dp[i][j] = dp[i - 1][j];
// dp[i][j] = dp[i - 1][j];
// if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i][j - v[i]] + w[i]);
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
// cout << dp[N][V] << endl;
cout << dp[V] << endl;
return 0;
}
状态表示:f(i, j):将第[i, j]区间的石子合并为一堆石子的最小代价
状态计算:f(i, j) = min(f(i, k), f(k + 1, j))
xxxxxxxxxx
const int N = 305;
int n;
int s[N]; // 前缀和
int f[N][N];
using namespace std;
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> s[i], s[i] += s[i - 1];
for (int len = 2; len <= n; ++len) { //枚举区间长度
for (int l = 1; l + len - 1 <= n; ++l) { //枚举区间左端点
int r = l + len - 1; //获得右端点
f[l][r] = INF;
for (int k = l; k < r; ++k) { //合并区间
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
}
}
}
cout << f[1][n] << endl;
return 0;
}
状态表示:f(i, j): 在串a区间为[1, i]和串b区间为[1, j]的最长重复子序列长度
状态计算:f(i, j) = max(f(i - 1, j), f(i, j - 1), f(i - 1, j - 1) + 1),ai == bj,才存在f(i -1, j - 1) + 1
xxxxxxxxxx
f(i, j) = max(f(i - 1, j), f(i, j - 1));
if (ai == bj) f(i, j) = max(f(i, j), f(i - 1, j - 1) + 1);