2023CCPC河南站 E.矩阵游戏 [动态规划](暴力递归到动态规划)

2023CCPC河南站 E.矩阵游戏


思路:

高维DP [样本对应模型+类背包问题]

  1. 空间复杂度分析(需要三维转二维)

    • 题目限值: 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 //远远够
  2. 时间复杂度分析

    • 时间限值: 2s (10e8~10e9) 题目保证 ∑n*m≤2.5×10e5
      在这里插入图片描述
  3. 思路可行性分析

    • **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);

在这里插入图片描述

代码:

  • 尝试(递归)
// 在[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年的包袱, 踏上了一趟为了自己的旅程!

我们所奋起直追的未来, 是我们遥不可及的当下!

每日一题:

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值