CD 17 机器人到达指定位置方案数

题目描述
假设有排成一行的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;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值