https://www.luogu.org/problemnew/show/P1854
题目描述
某花店现有编号由 1 到 F 的 F 束花, 每一束花的品种都不一样. 编号由 1 到 V 的 V 个花瓶被按顺序摆成一行, 花瓶的数量至少和花的数量相同. 现在要把所有花放到花瓶中, 规定每个花瓶最多只能放一束花, 且 ∀ i < j, 第 i 束花必须放在第 j 束花的左侧.
每个花瓶的形状和颜色不同, 因此放入不同的花会产生不同的美学效果. 空花瓶的美学值为 0. 请你给出一种方案, 使得总美学值最大.
输入输出格式
输入格式:
第一行有两个整数 F 和 V, 分别为花束数和花瓶数 ( 1 ≤ F ≤ V ≤ 100 ).
第二行到第 F + 1 行, 每行有 V 个整数. 第 i 行的第 j 个整数代表花束 i 放到花瓶 j 中的美学值.
输出格式:
第一行输出一个整数,为最大美学值.
第二行输出 F 个整数, 表示每束花放入的花瓶的编号.
输入输出样例
输入样例:
3 5
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20
输出样例:
53
2 4 5
实现
- 状态转移方程
设 f[i][j] 为将编号 1 到 i 的花束放入编号 1 到 j 的花瓶中时最大的美学值, a[i][j]为将第 i 束花放入第 j 个花瓶所能产生的美学值, 有 f[i][j] = max(f[i - 1][j - 1] + a[i][j], f[i][j - 1]).
- 滚动数组
可以省去表示花束的一维, 用 f[i] 表示在前 i 个花瓶中放入当前数量花束的最大美学值.
例如, 对于样例, 可以按如下方法计算:
初始状态:
i | 0 | 1 | 2 | 3 | 4 | 5 |
f[i] | 0 | 0 | 0 | 0 | 0 | 0 |
考虑第一束花后:
i | 0 | 1 | 2 | 3 | 4 | 5 |
f[i] | 0 | 7 | 23 | -5 | -24 | 16 |
∵ 此时 f[i] 表示在前 i 个花瓶中放入第一束花的最大美学值.
∴ ∀ i > j, f[i] ≥ f[j], f 数组应修改为:
i | 0 | 1 | 2 | 3 | 4 | 5 |
f[i] | 0 | 7 | 23 | 23 | 23 | 23 |
以此类推, 考虑第二束花:
i | 0 | 1 | 2 | 3 | 4 | 5 |
f[i] | 0 | 0 | 28 | 19 | 33 | 46 |
i | 0 | 1 | 2 | 3 | 4 | 5 |
f[i] | 0 | 0 | 28 | 28 | 33 | 46 |
考虑第三束花:
i | 0 | 1 | 2 | 3 | 4 | 5 |
f[i] | 0 | 0 | 0 | 24 | 8 | 53 |
i | 0 | 1 | 2 | 3 | 4 | 5 |
f[i] | 0 | 0 | 0 | 24 | 24 | 53 |
由此得到答案 53. 显然, 题目所要求的摆放方案可以在刷表的同时记录下来.
实现
1 #include <iostream> 2 #include <cstdio> 3 #define IsDigit(x) ((x) >= '0' && (x) <= '9') 4 using namespace std; 5 6 int f, v; 7 int in[101][101], dp[101], plan[101][101][2], s[101]; 8 9 10 int Read(void) 11 { 12 int c, ret(0), sign(false); 13 14 c = getchar(); 15 while (!IsDigit(c) && c != '-') 16 c = getchar(); 17 c == '-' && (sign = true, c = getchar()); 18 do 19 ret = ret * 10 + c - '0'; 20 while ((c = getchar()) && IsDigit(c)); 21 return sign ? -ret : ret; 22 } 23 24 25 int main() 26 { 27 int pos(0), nxt; 28 29 f = Read(); 30 v = Read(); 31 for (int i = 1; i <= f; ++i) 32 for (int j = 1; j <= v; ++j) 33 in[i][j] = Read(); 34 for (int i = 1; i <= f; ++i) { 35 for (int j = v - f + i; j >= i; --j) { 36 dp[j] = dp[j - 1] + in[i][j]; 37 plan[i][j][0] = plan[i - 1][j - 1][1]; 38 plan[i][j][1] = j; 39 } 40 for (int j = i + 1; j <= v - f + i; ++j) 41 dp[j - 1] > dp[j] && 42 (dp[j] = dp[j - 1], plan[i][j][0] = plan[i][j - 1][0], plan[i][j][1] = plan[i][j - 1][1]); 43 } 44 nxt = v; 45 for (int i = f; i; --i) { 46 s[pos++] = plan[i][nxt][1]; 47 nxt = plan[i][nxt][0]; 48 } 49 printf("%d\n", dp[v]); 50 for (int i = pos - 1; i >= 0; --i) 51 printf("%d ", s[i]); 52 printf("\n"); 53 return 0; 54 }