题目描述
假设有排成一行的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+710
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∗k),空间复杂度O(N)O(N)。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[5007][5007]; //i表示步数,j表示位置 ,
//状态转移方程 dp[i+1][j-1]+=dp[i][j] and dp[i+1][j+1]+=dp[i][j] ;当j=1时, dp[i+1][j+1]+=dp[i][j] ;当j=n时, dp[i+1][j-1]+=dp[i][j]
const long long inf= 1e9+7;
int main()
{
int n,m,k,p;
scanf("%d%d%d%d",&n,&m,&k,&p);
dp[0][m]=1;
for(int i=1;i<=k;i++)//遍历步数
{
for(int j=1;j<=n;j++)//遍历位置
{
if( dp[i-1][j]!=0 )
{
// cout<<"i:"<<i<<" j:"<<j<<endl;
if(j==1)
dp[i][j+1]=dp[i-1][j]%inf;
else if(j==n)
dp[i][j-1]+=dp[i-1][j]%inf;
else
{
dp[i][j+1]+=dp[i-1][j]%inf;
dp[i][j-1]+=dp[i-1][j]%inf;
}
}
}
}
// for(int j=0;j<=k;j++)
// {
// for(int i=1;i<=n;i++)
// {
// cout<<dp[j][i]<<" ";
// }
// cout<<endl;
// }
cout<<dp[k][p]%inf<<endl;//上面的取余,写法不好,所以最后需要再取余一次
return 0;
}
空间优化:
#include<stdio.h>
#include<algorithm>
using namespace std;
long long md=1000000007;
int main()
{
int n,m,k,p;
int dp[5010]={0},a[5010]={0};
//递推状态方程i==1: dp[i]=a[i+1]; i==n: dp[n]=a[n-1]; dp[i]=a[i-1]+a[i+1];
//这里dp[i],a[i]都表示走到i位置所花费的步数,a[i]用来存储上一次的位
//置,因为如果只用dp[i]来递推,举例:5 2 3 3. 第一步时dp[1]=1,dp[2]此
//时应该为0,但是dp[i]=dp[i-1]+dp[i+1]=1.此时dp[1]的的、值已经改变导致dp[2]的值改变.
scanf("%d%d%d%d",&n,&m,&k,&p);
fill(dp,dp+n+1,0);
fill(a,a+n+1,0);
a[m]=1;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=n;j++)
{
if(j==1)
{
dp[j]=a[j+1];
}
else if(j==n)
{
dp[j]=a[j-1];
}
else
{
dp[j]=(a[j-1]+a[j+1])%md;
}
}
for(int z=0;z<=n;z++)
{
a[z]=dp[z];//跟新a[i]数组
}
}
printf("%d",dp[p]);
return 0;
}
看了书之后对代码进行优化
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int inf=1e9+7;
int dp[5007];
int main()
{
int n,m,k,p;
scanf("%d%d%d%d",&n,&m,&k,&p);
dp[m]=1;
for(int i=0;i<k;i++)//k步
{
int left=dp[0];
for(int j=1;j<=n;j++)//遍历位置
{
int x= dp[j];
dp[j]=(left+dp[j+1])%inf;
left=x;
}
}
cout<<dp[p];
return 0;
}