问题 J: 传球游戏---------------------------dp/记忆化搜索+思维

题目描述
上体育课时,墨老师经常带着同学们一起做游戏。这次,墨老师带着同学们一起做传球游戏,游戏规则是这样的:N个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时拿着球没传出去的那个同学就是败者,要给大家表演一个节目。

聪明的张琪曼提出一个有趣的问题:有多少种不同的传球方法可以使得从张琪曼手里开始传的球,传了M次以后,又回到张琪曼手里。两种传球的方法被称作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并假设张琪曼为1号,球传了3次回到张琪曼手里的方式有1à2à3à1和1à3à2à1,共两种。
输入
有两个用空格隔开的整数N,M(3≤N≤30,1≤M≤30)。
输出
有一个整数,表示符合题目的方法数。
样例输入 Copy
3 3
样例输出 Copy
2

解析:
两种做法。
第一种:dp;
第二种:记忆化搜索

dp:
我们设f[i][j]表示移动第i次,第j个位置上
那么状态方程很简单 f[i][j]=f[i-1][j-1]+f[i-1][j+1]
第i次的状态肯定由第i-1次状态转移过来,左边和右边过来。

最后输出f[m][1] 移动m次,回到了1这个位置上


#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int f[N][N];//表示第i次,第j个位置 
int n,m;
int main()
{
	cin>>n>>m; 
	f[0][1]=1;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
		{
			if(j==1) f[i][j]=f[i-1][n]+f[i-1][2];
			else if(j==n) f[i][j]=f[i-1][1]+f[i-1][n-1];
			else f[i][j]=f[i-1][j-1]+f[i-1][j+1];
		 } 
	cout<<f[m][1]<<endl;
}

记忆化搜索:
f[i][j]:表示第i个位置,剩j步


#include<bits/stdc++.h>
using namespace std;
int f[50][50];//第i个位置,剩下j步 
int n,m;
void dfs(int x,int cnt)
{
	f[x][cnt]=0;
	if(x==1&&cnt==m) //满足条件第1个位置,正好移动M次
	{
		f[x][cnt]=1;
		return ;
	}
	if(cnt==m) return ; //剪纸,虽然满足移动m次,但不满足在1的位置上
	int a;
	//搜索左边 
	a=x==1 ? n: x-1;//判断边界
	//==-1表示没搜过 
	if(f[a][cnt+1]==-1) dfs(a,cnt+1);//往左边搜
	if(f[x%n+1][cnt+1]==-1) dfs(x%n+1,cnt+1);//往右边搜
	f[x][cnt]=f[a][cnt+1]+f[x%n+1][cnt+1]; //回溯
}
int main()
{
	memset(f,-1,sizeof f);
	cin>>n>>m;
	dfs(1,0); 
	cout<<f[1][0]<<endl; //在1的位置上,剩0步
}

发布了383 篇原创文章 · 获赞 7 · 访问量 8056

猜你喜欢

转载自blog.csdn.net/qq_43690454/article/details/104162858