constint N = 1010; int n, m; int v[N], w[N]; int f[N];
intmain() { 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;
return0; }
/* #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; } */
AcWing 3. 完全背包问题
状态表示
$f(i, j)$ 表示容量 j 的条件下, 前 i 件物品的最优解
状态计算
$f(i, j) = max(f(i - 1, j - k v) + k w), k = 0, 1, 2 …(j >= k v)$ 等价变形
intmain() { 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;
return0; }
//优化版 /* #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][j - v[i]] + w[i]); } cout << f[n][m] << endl; return 0; } */
//朴素法 /* #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; } */
AcWing 4. 多重背包问题
状态计算
$f(i, j) = max(f(i - 1, j), f(i - 1, j - k v) + k w)$
intmain() { cin >> n >> m; for(int i = 0; i < n; i ++ ) { int v, w, s; cin >> v >> w >> s; for(int j = m; j >= 0; j -- ) for(int k = 1; k <= s && k * v <= j; k ++ ) f[j] = max(f[j], f[j - k * v] + k * w); }
cout << f[m] << endl;
return0; }
AcWing 5. 多重背包问题 II
状态计算
$f(i, j) = max(f(i - 1, j), f(i - 1, j - k v) + k w)$
int cnt = 0; for(int i = 1; i <= n; i ++) { int a, b, s; cin >> a >> b >> s; int k = 1; while(k <= s) { cnt ++; v[cnt] = a * k; w[cnt] = b * k; s -= k; k *= 2; } if(s > 0) { cnt ++; v[cnt] = a * s; w[cnt] = b * s; } }
n = cnt;
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]);
intmain() { scanf("%d", &n); for(int i = 1; i <= n; i ++ ) scanf("%d", &s[i]); //前缀和,便于计算 for(int i = 1; i <= n; i ++ ) s[i] += s[i - 1];
for(int len = 2; len <= n; len ++ ) //len 表示区间长度 for(int i = 1; i + len - 1 <= n; i ++ ) // { int l = i, r = i + len - 1; //l为起点, r为终点 f[l][r] = 0x3f3f3f3f; for(int k = l; k < r; k ++ ) //k为分界点,用于状态计算 f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + s[r] - s[l - 1]); }
//截取num的 第 l ~ r 位数字 intget(vector<int> num, int l, int r) { int res = 0; for(int i = l; i >= r; i -- ) res = res * 10 + num[i]; return res; }
//计算10的x次幂 intpower10(int x) { int res = 1; while (x -- ) res *= 10; return res; }
intcount(int n, int x) { if (!n) return0;
//用数组存储数字 n ,便于取每个位上的数字 vector<int> num; while (n) { num.push_back(n % 10); n /= 10; } n = num.size();
int res = 0; //最高位不能为 0 , x == 0 时,可以少循环一次 //计算 x 在每位数字上面出现的次数, 加起来就是总共的出现次数 for (int i = n - 1 - !x; i >= 0; i -- ) { // i == n - 1时,是数字的个位,不需要乘上10的幂次 if (i < n - 1) { //abc * power10(i) res += get(num, n - 1, i + 1) * power10(i);
//计算0的出现次数时,数字首位不能为0 //即 当 x == 0 时, abc 不能为 000 if (!x) res -= power10(i); }
//d == x 的情况 if (num[i] == x) res += get(num, i - 1, 0) + 1; // d > x 的情况 elseif (num[i] > x) res += power10(i); } cout << num[n - 1] << " "; return res; }
intmain() { int a, b; while (cin >> a >> b , a) { if (a > b) swap(a, b);
for (int i = 0; i <= 9; i ++ ) cout << count(b, i) - count(a - 1, i) << ' '; cout << endl; }
for (int i = 0; i < 1 << n; i ++ ) //枚举所有路径 for (int j = 0; j < n; j ++ ) //枚举所有点 if (i >> j & 1) //路径 i 是否经过点 j for (int k = 0; k < n; k ++ ) //枚举走到 j 的点 k if (i >> k & 1) //判断到达 j 的点 k 是否为最优路径 f[i][j] = min(f[i][j], f[i - (1 << j)][k] + w[k][j]);
//偏移量,使当前坐标偏移 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
intdp(int x, int y) { int& v = f[x][y];
//该点已经被遍历过 if(v != -1) return v;
v = 1;
//思路类似于BFS for(int i = 0; i < 4; i ++ ) { int a = x + dx[i], b = y + dy[i];
//确保当前的坐标值未出界,并且对应的高度可以下滑 //这一步可以将遍历过的坐标对应可以下滑的最大值记录进f数组 if(a >= 1 && a <= n && b >= 1 && b <= m && h[a][b] < h[x][y]) v = max(v, dp(a, b) + 1); }
return v; }
intmain() { cin >> n >> m;
for(int i = 1; i <= n; i ++ ) for(int j = 1; j <= m; j ++ ) cin >> h[i][j]; memset(f, -1, sizeof f);
int res = 0, x, y; for(int i = 1; i <= n; i ++ ) for(int j = 1; j <= m; j ++ ) { if(res < dp(i, j)) { res = dp(i, j); x = i, y = j; } } cout << res << endl;
// while(!q.empty()) { // auto t = q.front(); // path.push_back(t); // q.pop(); // x = t.first, y = t.second; // for(int i = 0; i < 4; i ++ ) { // auto a = x + dx[i], b = y + dy[i]; // if(a >= 1 && a <= n && b >= 1 && b <= m && h[a][b] == h[x][y] - 1) // q.push({a, b}); // } // }