【题目描述】
假设有排成一行的N个位置,记为1~N,开始时机器人在M位置,机器人可以往左或者往右走,如果机器人在1位置,那么下一步机器人只能走到2位置,如果机器人在N位置,那么下一步机器人只能走到N-1位置。规定机器人只能走k步,最终能来到P位置的方法有多少种。由于方案数可能比较大,所以答案需要对1e9+7取模。
输入描述:
输出包括一行四个正整数N(2<=N<=5000)、M(1<=M<=N)、K(1<=K<=5000)、P(1<=P<=N)。
输出描述:
输出一个整数,代表最终走到P的方法数对10^9+7模后的值。
【示例1】
输入
5 2 3 3
输出
3
说明
1).2->1,1->2,2->3
2).2->3,3->2,2->3
3).2->3,3->4,4->3
【示例2】
输入
1000 1 1000 1
输出
591137401
说明
注意答案要取模
备注:
时间复杂度O(n*k),空间复杂度O(N)。
【代码实现 - 暴力递归】
#include<iostream>
using namespace std;
int mod = 1e9 + 7;
/*
* Method to calculate the ways of acheiving arbitrary point
* There are three scenarios:
* 1. cur==1, the next step only to right
* 2. cur==n, the next step only to left
* 3. cur!=1 && cur!=n, the next step can be left or right
* Note that, after each step, rest=rest-1
*/
int way(int n, int cur, int rest, int p) {
if (2 > n || 5000 < n || 1 > cur || n < cur || 1 > rest || 5000 < rest || 1 > p || n < p) {
return 0;
//throw out_of_range("Input parameter(s) invalid, please check!\n");
}
if (0 == rest) {
return cur == p ? 1 : 0;
}
if (1 == cur) {
return way(n, cur+1, rest-1, p);
} else if (n == cur) {
return way(n, cur-1, rest-1, p);
} else {
return way(n, cur-1, rest-1, p) + way(n, cur+1, rest-1, p);
}
}
int main() {
int n, m, k, p;
cin >> n >> m >> k >> p;
int cnt = 0;
for (int i=1; i<=n; i++) {
cnt += way(i, m, k, p);
}
cout << cnt%mod <<endl;
return 0;
}
上述代码可以清晰的表示该题的解决思路,简单易懂,但是在问题规模比较大的时,容易陷入递归地狱,最终导致运行程序的机器资源耗尽。如果是在线编程,则会出现如下超时现象:
运行超时: 您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。Case通过率为0.00%
【代码实现 - 动态规划】
#include<iostream>
#include<vector>
using namespace std;
int mod = 1e9 + 7;
/*
* 暴力递归优化为动态规划的条件:确认问题是否具备无后效性。
* 当前问题中:来到某一个位置P后还剩余K步的走法仅仅与其后续走法相关,而与之前是如何来到P位置毫无关联,故其符合无后效性。
* 优化步骤如下:
* 1. 寻找影响递归状态的可变参数;
* 2. 基于可变参数建立映射表,并标记出目标位置
* 3. 根据递归中的base case计算其他未知位置的值
* 4. 返回目标位置对应的数值
*/
int way2(int n, int cur, int rest, int p) {
// 依据cur和rest建立二维映射表
vector<vector<int>> dp(rest+1, vector<int>(n+1, 0));
// rest==0时,只有目标位置dp[0][p]=1
dp[0][p] = 1;
// 其他位置求解参照way()方法
for (int row=1; row<=rest; row++) {
for (int col=1; col<=n; col++) {
if (1 ==col) {
dp[row][col] = dp[row-1][2]%mod;
} else if (n == col) {
dp[row][col] = dp[row-1][n-1]%mod;
} else {
dp[row][col] = (dp[row-1][col-1] + dp[row-1][col+1])%mod;
}
}
}
return dp[rest][cur]%mod;
}
int main() {
int n, m, k, p;
cin >> n >> m >> k >> p;
if (2 > n || 5000 < n || 1 > m || n < m || 1 > k || 5000 < k || 1 > p || n < p) {
return 0;
}
cout << way2(n, m, k, p) <<endl;
return 0;
}
【代码实现 - 动态规划+空间压缩】