当前位置: 首页 > news >正文

Problem E. 矩阵游戏 (2023年ccpc河南省赛)

原题链接:
https://codeforces.com/gym/104354

题意:

有一个n*m的矩阵,只有三种字符:0,1和?。从[1,1]走到[n,m],每次只能向下走或者向下走。当走到1的时候得一分,走到0的时候不得分,走到?的时候可以将他变为1从而得到一分,或者不变,求所有从[1,1]走到[n,m]的路径的得分的最大值

思路:

f[i][j][k]表示走到[i,j]恰好有k个?变成1的方案数的最大得分
状态转移:
a[i][j]‘0’:f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k])
a[i][j]
‘1’:f[i][j][k]=max(f[i-1][j][k]+1,f[i][j-1][k]+1)
a[i][j]==‘?’:
改:f[i][j][k]=max(f[i-1][j][k-1]+1,f[i][j-1][k-1]+1)
不改:f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k])

那么这样的空间复杂度是n* m * x,会mle

于是考虑将数组优化到二维:f[j][k]

1.将k从大到小枚举
在转移的时候,如果按正常枚举,就会出现重复的情况,这时候只需要将k从大到小进行枚举,就避免了重复

#include<bits/stdc++.h>
using namespace std;
int n,m,x;
int f[505][1005];
char a[505][505];
bool  cheek(int x,int y){if(x>=1&&x<=n&&y>=1&&y<=m) return true;else return false;
}
void sove(){scanf("%d%d%d",&n,&m,&x);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>a[i][j];}}for(int j=0;j<=m;j++){for(int k=0;k<=x;k++){f[j][k]=-0x3f3f3f3f;}}if(a[1][1]=='1'){f[1][0]=1;}else if(a[1][1]=='0'){f[1][0]=0;}else{f[1][1]=1;f[1][0]=0;}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){for(int k=x;k>=0;k--){if(a[i][j]=='1'){if(cheek(i-1,j)){f[j][k]=max(f[j][k],f[j][k]+1);}if(cheek(i,j-1)){f[j][k]=max(f[j][k],f[j-1][k]+1);}}else if(a[i][j]=='0'){if(cheek(i,j-1)){f[j][k]=max(f[j][k],f[j-1][k]);}				}else{if(cheek(i-1,j)){if(k-1>=0) f[j][k]=max(f[j][k],f[j][k-1]+1);}if(cheek(i,j-1)){f[j][k]=max(f[j-1][k],f[j][k]);if(k-1>=0)f[j][k]=max(f[j][k],f[j-1][k-1]+1);}		}}}}int ans=0;for(int i=0;i<=x;i++){ans=max(ans,f[m][i]);}cout<<ans<<endl;
}
int main(){int t;scanf("%d",&t);while(t--){sove();}return 0;
}

2.滚动数组
在转移的时候只用到了i和i-1层,那么我们就将i这一维开两个,在转移的时候在两维之间相互转移就可以了

#include<bits/stdc++.h>
using namespace std;
int n,m,x;
int f[3][505][1005];
char a[505][505];
bool  cheek(int x,int y){if(x>=1&&x<=n&&y>=1&&y<=m) return true;else return false;
}
void sove(){scanf("%d%d%d",&n,&m,&x);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>a[i][j];}}for(int i=0;i<3;i++){for(int j=0;j<=m;j++){for(int k=0;k<=x;k++){f[i][j][k]=-0x3f3f3f3f;}}
}if(a[1][1]=='1'){f[1][1][0]=1;}else if(a[1][1]=='0'){f[1][1][0]=0;}else{f[1][1][1]=1;f[1][1][0]=0;}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){for(int k=0;k<=x;k++){if(a[i][j]=='1'){if(cheek(i-1,j)){f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j][k]+1);}if(cheek(i,j-1)){f[i&1][j][k]=max(f[i&1][j][k],f[i&1][j-1][k]+1);}}else if(a[i][j]=='0'){if(cheek(i-1,j)){f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j][k]);}if(cheek(i,j-1)){f[i&1][j][k]=max(f[i&1][j][k],f[i&1][j-1][k]);}				}else{if(cheek(i-1,j)){f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j][k]);if(k-1>=0)f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j][k-1]+1);}if(cheek(i,j-1)){f[i&1][j][k]=max(f[i&1][j][k],f[i&1][j-1][k]);if(k-1>=0)f[i&1][j][k]=max(f[i&1][j][k],f[i&1][j-1][k-1]+1);}	}}}}int ans=0;for(int i=0;i<=x;i++){ans=max(ans,f[n&1][m][i]);}	cout<<ans<<endl;
}
int main(){int t;scanf("%d",&t);while(t--){sove();}return 0;
}
http://www.lryc.cn/news/65759.html

相关文章:

  • 数字孪生模型构建理论及应用
  • Vue面试题:30道含答案和代码示例的练习题
  • 2023-05-09 LeetCode每日一题(有效时间的数目)
  • 第三节课 Linux文件权限
  • 开发STC89C51系列单片机需要的单片机技术
  • 分布式键值存储是什么?(分布式键值存储大值)
  • 多线程(线程同步和互斥+线程安全+条件变量)
  • Flutter学习——开发Flutter需要的技能
  • SPSS如何进行因子分析和主成分分析之案例实训?
  • 图标字体与HTML转义字符:网页设计中的两个关键概念
  • Elasticsearch详解
  • 学习笔记(13)网络基础
  • LeertCode 134 加油站
  • python文件操作的基本流程
  • 1. 两数之和
  • 操作系统:06 进程通信
  • WRF模式
  • 2直接连接的网络与VLAN划分【实验】【计算机网络】
  • 【Linux0.11代码分析】04 之 head.s 启动流程
  • 自动化测试和selenium的使用
  • Ubuntu常用终端操作
  • Spring Security 6.x 系列【34】认证篇之前后端分离场景下的集成方案
  • Qt之QTextToSpeech 让你的应用程序说话
  • 为什么程序员喜欢用Linux?
  • leetcode 598. 范围求和 II
  • javaweb前置知识
  • 基于微信小程序的酒店预定管理系统设计与实现
  • 26. Service——深入学习
  • 【算法】Check If Word Is Valid After Substitutions 检查替换后的词是否有效
  • 基于jenkinsfile布置java工程