2023CCPC河南站 E.矩阵游戏
思路:
高维DP [样本对应模型+类背包问题]
-
空间复杂度分析(需要三维转二维)
- 题目限值: 256MB=256×10e6=2.56×10e8 个int
- 三维: 总需要空间: dp[500][500][1000]:500×500×1000=2.5×10e8 // 太极限了, 同时你还要算上 输入数据的大小, dp要多开10几个, 必然MLE, 所以要优化到二维
- 二维: 总需要空间: dp[500][1000]=500×1000=5×10e5 //远远够
-
时间复杂度分析
- 时间限值: 2s (10e8~10e9) 题目保证 ∑n*m≤2.5×10e5
- 时间限值: 2s (10e8~10e9) 题目保证 ∑n*m≤2.5×10e5
-
思路可行性分析
-
**basic case: **出界返回0,
if(x<1||x>n||y<1||y>m) return 0; // 越界返回空气
-
else:
-
要是为1, 为了使得最大, 就得加上, 再在向右|向下中选择最大值
if(arr[x][y]=='1') return 1+max(way1(x,y+1,rest), way1(x+1,y,rest));
-
要是为0, 在向右|向下中选择最大值
else if(arr[x][y]=='0') return max(way1(x,y+1,rest), way1(x+1,y,rest));
-
要是为?,
- 能换, 当前的rest>=1:
int p1=1+max(way1(x,y+1,rest-1), way1(x+1,y,rest-1));
- 换不了:
int p2=max(way1(x,y+1,rest), way1(x+1,y,rest));
当前换不换, 看最大
return max(p1, p2);
- 能换, 当前的rest>=1:
-
-
代码:
- 尝试(递归)
// 在[x,y]的位置, 有rest步可以变
// 返回值: 走到[n,m]处的最大价值
int way1(int x,int y,int rest) {
if(x<1||x>n||y<1||y>m) return 0; // 越界返回空气
else {
if(arr[x][y]=='1') return 1+max(way1(x,y+1,rest), way1(x+1,y,rest));
else if(arr[x][y]=='0') return max(way1(x,y+1,rest), way1(x+1,y,rest));
else {
int p1=max(way1(x,y+1,rest), way1(x+1,y,rest));
if(rest>=1) p1=max(p1, 1+max(way1(x,y+1,rest-1), way1(x+1,y,rest-1)));
return p1;
}
}
}
- 记忆化搜索MLE
- 转严格表依赖, 因为任意一个位置只与x+1层有关系, 那可以三维->二维,
#include <iostream>
#include <cstring>
using namespace std;
const int N=510, M=1010;
char arr[N][N];
int n, m, p, dp[N][M];
int main() {
int T;scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>arr[i][j];
memset(dp,0,sizeof dp);
for(int x=n;x>=1;x--) {
for(int y=m;y>=1;y--) {
for(int rest=p;rest>=0;rest--) {
if(arr[x][y]=='1') dp[y][rest]=1+max(dp[y+1][rest], dp[y][rest]);
else if(arr[x][y]=='0') dp[y][rest]=max(dp[y+1][rest], dp[y][rest]);
else {
int p1=max(dp[y+1][rest], dp[y][rest]);
if(rest>=1) p1=max(p1, 1+max(dp[y+1][rest-1], dp[y][rest-1]));
dp[y][rest]=p1;
}
}
}
}
cout<<dp[1][p]<<"\n";
}
return 0;
}
注意:
1. cin不会读取, 空格和换行; 所以这里得用cin读入, scanf得加getchar();
2. 转二维, rest的是1000, 得开dp[510][1010];
最开始先入为主了, 开成dp[510][510]卡半天;
3. 牢记动态规划问题的解决方法:
严格遵循 暴力递归->记忆化搜索->转严格表结构 + 归纳大量的模型(背包,线性…)
心得:
(2023.5)去年大一, 去现场打的这界比赛, 当时三个人大眼瞪小眼, 在那傻坐了5个小时, 就AC了打卡题
(2023.8)学完cpp和面向对象以及STL和基本数据结构: 开始学算法, 中途多次拿出当时发的题本, 翻了一边又一边, 当我每学一个算法, 我找找看有没有能有思路的题, 终于今天(2024.1.10)AC了第一道当年望而却步的题目
2024.1.9这一天: 我终于卸下了过往积攒了6年的包袱, 踏上了一趟为了自己的旅程!