Mio visits ACGN Exhibition(dp,思维)

19 篇文章 0 订阅
本文介绍了一种解决从地图起点到终点的路径问题,要求路径中0和1的数量满足特定条件的高效算法。通过DP方法,只记录0的数量,巧妙地避免了大规模状态空间。核心思路是利用dp[i][j][k]来表示当前位置及0的数量,有效减少了内存消耗。
摘要由CSDN通过智能技术生成

传送门
题目:
在这里插入图片描述

示例1
输入

2 2 1 1
0 0
1 1
输出

2
示例2
输入

3 3 2 0
0 0 1
0 0 1
1 0 0
输出
6

题目大意:
给 出 n × m 的 地 图 , 其 中 每 个 格 子 上 存 1 / 0 , 求 从 ( 1 , 1 ) 到 ( n , m ) 的 路 径 中 所 有 满 足 0 的 个 数 至 少 有 p 个 、 1 的 个 数 至 少 有 q 个 的 路 径 总 数 给出 n\times m 的地图,其中每个格子上存1/0,求从(1,1)到(n,m)的路径中所有满足0的个数至少有p个、1的个数至少有q个的路径总数 n×m1/01,1n,m)0p1q

思路:
首 先 : 首先:
1. 如 果 用 d f s 去 寻 找 很 有 可 能 超 时 ; 1.如果用dfs去寻找很有可能超时; 1.dfs
2. 如 果 d p 用 四 维 数 组 分 别 存 放 x 轴 坐 标 、 y 轴 坐 标 和 0 、 1 的 个 数 那 么 会 超 内 存 2.如果dp用四维数组分别存放x轴坐标、y轴坐标和0、1的个数那么会超内存 2.dpxy01
所 以 : 所以:
需 要 我 们 换 个 角 度 去 解 题 ; 需要我们换个角度去解题;
由 分 析 我 们 可 以 发 现 , 无 论 走 哪 条 路 都 满 足 : 由分析我们可以发现,无论走哪条路都满足:
0 的 个 数 + 1 的 个 数 = n + m − 1 ; 0的个数 +1 的个数 = n+m-1; 0+1=n+m1;
由 此 可 得 : 1 的 个 数 = ( n + m − 1 ) − 0 的 个 数 由此可得:1的个数 = (n+m-1)-0的个数 1=(n+m1)0
所 以 : 可 以 通 过 d p 标 记 不 同 0 的 数 目 的 路 径 个 数 , 最 终 统 计 0 数 目 满 足 题 目 要 求 的 所 有 路 径 之 和 即 可 ; 所以:可以通过dp标记不同0的数目的路径个数,最终统计0数目满足题目要求的所有路径之和即可; dp00

优 化 过 后 d p [ i ] [ j ] [ k ] 代 表 含 义 : 优化过后dp[i][j][k]代表含义: dp[i][j][k]
i = 1 : 当 前 行 ; i = 0 : 上 一 行 ; j : 当 前 列 ; k : 0 的 个 数 i=1:当前行; i=0:上一行; j:当前列;k:0的个数 i=1:;i=0:;j:;k:0
d p [ 0 ] [ j ] [ k ] : 上 一 行 第 j 列 0 有 k 个 时 的 路 径 数 dp[0][j][k]: 上一行第j列0有k个时的路径数 dp[0][j][k]:j0k
d p [ 1 ] [ j ] [ k ] : 当 前 行 第 j 列 0 有 k 个 时 的 路 径 数 dp[1][j][k]: 当前行第j列0有k个时的路径数 dp[1][j][k]:j0k

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define int long long
const int N=1e3+10;
const int mod=998244353;

int a[510][510],dp[2][510][N];

signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n,m,p,q;
	cin>>n>>m>>p>>q;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)cin>>a[i][j];
	if(p+q>n+m-1){
		cout<<0<<endl;return 0;
	}
	if(a[1][1]){//起点为1时 
		dp[1][1][0]=1;
	}else dp[1][1][1]=1;//起点为0时 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i==1&&j==1)continue;
			if(a[i][j]){
				for(int k=0;k<n+m;k++)//更新当列不同0个数时的路径数 
					dp[1][j][k]=(dp[1][j-1][k]+dp[0][j][k])%mod;
			}else{
				dp[1][j][0]=0;//当前第j列有0个0的路径数目为0 
				for(int k=1;k<n+m;k++){
					dp[1][j][k]=(dp[1][j-1][k-1]+dp[0][j][k-1])%mod;
// 					cout<<dp[1][j][k]<<' ';
				}
			}
		}
		for(int j=1;j<=m;j++)//更新,将当前行置为下一次循环的上一行 
			for(int k=0;k<n+m;k++)dp[0][j][k]=dp[1][j][k];
	}
	ll ans=0;
	for(int i=p;i<=m+n-1-q;i++)ans=(ans+dp[0][m][i])%mod;
	cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值