题目背景
对应的选择、判断题:试题 - GESP 202409 C++ 七级 - 洛谷有题
题目描述
小杨有一个 n×m 的矩阵,仅包含 01? 三种字符。矩阵的行从上到下编号依次为 1,2,...,n,列从左到右编号依次为 1,2,...,m。小杨开始在矩阵的左上角 (1,1),小杨只能向下或者向右移动,最终到达右下角 (n,m) 时停止,在移动的过程中每经过一个字符 1 得分会增加一分(包括起点和终点),经过其它字符则分数不变。小杨的初始分数为 0 分。
小杨可以将矩阵中不超过 x 个字符 ? 变为字符 1。小杨在修改矩阵后,会以最优的策略从左上角移动到右下角。他想知道自己最多能获得多少分。
输入格式
第一行包含一个正整数 t,代表测试用例组数,接下来是 t 组测试用例。对于每组测试用例,一共 n+1 行。
第一行包含三个正整数 n,m,x,含义如题面所示。
之后 n 行,每行一个长度为 m 的仅含 01? 的字符串。
输出格式
对于每组测试用例,输出一行一个整数,代表最优策略下小杨的得分最多是多少。
输入输出样例
输入 #1复制
2
3 3 1
000
111
01?
3 3 1
000
?0?
01?
输出 #1复制
4
2
说明/提示
样例 1 解释
对于第二组测试用例,将 (2,1) 或者 (3,3) 变为 1 均是最优策略。
数据规模与约定
| 子任务编号 | 数据点占比 | t | n,m | x |
|---|---|---|---|---|
| 1 | 30% | ≤5 | ≤10 | =1 |
| 2 | 30% | ≤10 | ≤500 | ≤30 |
| 3 | 40% | ≤10 | ≤500 | ≤300 |
对全部的测试数据,保证 1≤t≤10,1≤n,m≤500,1≤x≤300,保证所有测试用例 n×m 的总和不超过 2.5×105。
代码实现:
cpp
#include <bits/stdc++.h>
using namespace std;
const int INF = -1e9;
const int MAXX = 305;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
int n,m,x;
cin >> n >> m >> x;
vector<string> s(n+1);
for(int i=1;i<=n;i++)
{
string tmp;
cin >> tmp;
s[i] = " " + tmp;
}
vector<vector<vector<int>>> dp(n+2, vector<vector<int>>(m+2, vector<int>(x+2, INF)));
if(s[1][1] == '1')
{
dp[1][1][0] = 1;
}
else if(s[1][1] == '0')
{
dp[1][1][0] = 0;
}
else
{
dp[1][1][0] = 0;
if(1 <= x) dp[1][1][1] = 1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i == 1 && j == 1) continue;
char c = s[i][j];
for(int k=0;k<=x;k++)
{
int up = INF, left = INF;
if(i>1) up = dp[i-1][j][k];
if(j>1) left = dp[i][j-1][k];
int pre = max(up, left);
if(pre == INF) continue;
if(c == '1')
{
dp[i][j][k] = max(dp[i][j][k], pre + 1);
}
else if(c == '0')
{
dp[i][j][k] = max(dp[i][j][k], pre);
}
else
{
dp[i][j][k] = max(dp[i][j][k], pre);
if(k+1 <= x)
{
dp[i][j][k+1] = max(dp[i][j][k+1], pre + 1);
}
}
}
}
}
int ans = 0;
for(int k=0;k<=x;k++)
{
ans = max(ans, dp[n][m][k]);
}
cout << ans << '\n';
}
return 0;
}