[题解] [洛谷 P1174] 打砖块
[洛谷 P1174] 打砖块
题目描述#
有
输入格式#
第一行有
接下来有
其中
所有的数与字符之间用一个空格隔开,行末没有多余的空格。
输出格式#
仅一个正整数,表示最大的得分。
题解#
不难看出该题需要使用动态规划解决。设计状态
1 Y
1 N
那么在打掉下面的 N 后,如果我们还剩下一颗子弹,就可以没有花费打掉 Y ,但如果我们在打完 N 后刚好用完了所有子弹,那么我们就无法再获得 Y 的分数。此外还有如下特殊情况:
1 N 1 Y
1 N 1 N
这种情况下,对于第二列,我们虽然可以以一颗子弹的花费获得两个砖块的分数,但是我们需要用到两颗子弹。因此,我们需要考虑最后一颗子弹是否在这一列打完。如果最后一颗子弹在这一列打完,我们就无法通过“借用”子弹的方式获得 Y 的分数,否则我们就可以无花费的打掉 Y 。特别的,如果我们在当前列花费的子弹数小于总子弹数,那么我们一定可以无花费的打掉 Y 。
因此,我们需要记录两种状态:
AC代码#
#include <algorithm>
#include <iostream>
#define int long long
using namespace std;
const int MAXN = 1003;
int f[MAXN][MAXN];
char c[MAXN][MAXN];
int dp1[MAXN][MAXN]; //dp_i,j: 考虑前i列,花费j颗子弹,最后一颗子弹打在这一列的最高分数
int dp2[MAXN][MAXN]; //dp_i,j: 考虑前i列,花费j颗子弹,最后一颗子弹不打在这一列的最高分数
int sum1[MAXN][MAXN], sum2[MAXN][MAXN]; // sum:分数的前缀和
int n, m, k;
signed main() {
// 数据输入
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> f[i][j] >> c[i][j];
}
}
// 初始化sum
for (int i = 1; i <= m; i++) {
int cnt = 0;
for (int j = n; j > 0; j--) {
if (c[j][i] == 'Y') {
sum1[i][cnt] += f[j][i]; // 这一列可以预支
} else {
cnt++;
sum1[i][cnt] = sum2[i][cnt] = sum1[i][cnt - 1] + f[j][i];
}
}
}
// dp
for (int j = 1; j <= m; j++) { // 列数
for (int i = 0; i <= k; i++) { // 消耗的总子弹数
for (int l = 0; l <= min(n, i); l++) { // 在当前列消耗的子弹数
dp1[j][i] = max(dp1[j][i], dp1[j - 1][i - l] + sum1[j][l]); // 如果当前这一列不是最后打到的,就可以无脑预支
if (l != 0) dp2[j][i] = max(dp2[j][i], dp1[j - 1][i - l] + sum2[j][l]); // 不预支的情况
if (l < i) dp2[j][i] = max(dp2[j][i], dp2[j - 1][i - l] + sum1[j][l]); // 一定可以预支的情况
}
}
}
cout << dp2[m][k] << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效