上学路线 DP基础

本文探讨了一个典型的组合问题——求解从网格左上角到右下角的不同路径数量,当使用传统组合公式因数据规模过大导致溢出时,采用动态规划(DP)方法有效解决了这一难题。通过构建二维数组或优化后的向量存储方案,实现路径计数的同时避免了溢出,最终输出结果对1000000007取余。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天遇到遇到的一道题目,上学路线,咋一看是一个很简单的高中学的组合问题,但是难就难在题目所给的数据太大,long long 类型也会溢出,导致结果不准确,思考过后发现这个题目的正解应该是用DP来做

题目如下:
上学路线:

小D从家到学校的道路结构是这样的:由n条东西走向和m条南北走向的道路构成了一个n*m的网格,
每条道路都是单向通行的(只能从北向南,从西向东走)。已知小D的家在网格的左上角,学校在网
格的右下角。问小D从他的家到学校一共有多少种不同的上学路线。
小D上学路线数量,结果对1000000007取余。


两个正整数n和m,意义如题目所述。
100%的数据,n,m≤1000

在这里插入图片描述
按照排列组合的做法很简单,题目规定只能朝右和下走,如图所示时,向右需要走三步,向下需要走两步,总共走五步就能到达学校,我们只要在这五步中任意选两步向下走,其余三步向右走自然就能到达学校。所以答案即是
在这里插入图片描述
于是我们可以得出解的公式:
在这里插入图片描述
但是很遗憾就算long long类型也是存不下1000的阶乘的,我当时考虑了在计算阶乘时对中间结果进行取余,但是最后结果就会错了,于是还是得用到DP才行。

DP解法:

代码如下:

#include<iostream>
#pragma GCC optimize(3)
#pragma G++ optimize(3) 
using namespace std;
int dot[1005][1005];
int main() {    
	ios::sync_with_stdio(false); 
	
	int n, m;   
	cin >> n >> m;  
	
	for (int i = 1; i <= n; i++)    
		dot[i][1] = 1;  
	for (int i = 1; i <= m; i++)   
		dot[1][i] = 1; 
		
	for (int i = 2; i <= n; i++)  
		for (int j = 2; j <= m; j++)    
			dot[i][j] = (dot[i - 1][j] + dot[i][j - 1]) % 1000000007; 
			
	cout << dot[n][m] % 1000000007 << endl;  
	return 0;
}
DP思路:

因为题目规定只能朝右或下走,所以每一点最多可以由左或上两个方向出发,假设每一点所保存的为到达该点的线路总和,所以得出公式:

dot[x][y]=dot[x-1][y]+dot[x][y-1]

同时在每一点的结果计算出来后,对该结果取余,防止溢出
在这里插入图片描述
图中每点的数字代表到达该点的所有方式

不得不说,这段代码很不美直接开了一个(1005,1005)的二维数组,这种暴力的做法真的很野蛮,鉴于OJ对时复杂度的高要求,实属没办法,于是我重新写了一段优美的代码如下:

#include<vector>
#include<iostream>
#define MODNUM 1000000007

using namespace std;
int main(){
	int n,m;
	cin>>n>>m;

	vector<long long> line(m,1);
	vector<vector<long long>> dot;

	dot.resize(n);
	dot[0]=line;
	line.clear();

	for(int i=1;i<n;i++){
		line.resize(m);
		line[0];

		for(int j=1;j<m;j++){
			line[j]=(line[j-1]+dot[i-1][j])%MODNUM;

		dot[i]=line;
		line.clear();
	}
	
	cout<<dot[n-1][m-1]<<endl;
	return 0;
}

运行结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Dizzrt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值