题目连接
- 该题是luogu试炼场的2-12:T3
题目大意
- 有n 个小朋友,玩击鼓传花的游戏,小球只能传给左边或者右边的同学;
- 要求第m次传回给出发者,问方案数量;
题目分析
-
看题目第一反应当然是DFS,但显然是需要优化的:
-
解题思路1
- 直接DFS,肯定是不能过的,先拿部分分安慰一下自己嘛!
代码1:50分
- 吃果果的dfs,不做任何优化
//luogu1057:传球游戏
//50分解题思路:
//直接dfs
#include<cstdio>
int n,m,ans=0;
void dfs(int x,int t)//当前是 x 号同学, 串了 t次
{
if(t==m&&x!=1) return ;//超过 m 次,结束
if(t==m&&x==1) //球回到了手上
{
ans++;
return ;
}
//右传
if(x+1>n) dfs(1,t+1);
else dfs(x+1,t+1);
//左传
if(x-1==0) dfs(n,t+1);
else dfs(x-1,t+1);
}
int main()
{
scanf("%d %d",&n,&m);
dfs(2,1);// 从 1 出发,右传
dfs(n,1);// 左传
printf("%d",ans);
return 0;
}
思路2:dfs+记忆化
- 暴搜过不了的题,一般两条路:想剪枝/ 想DP
- 先想剪枝!!:因为已经有了DFS的底板,只是做拓展的思维分析,赛场上的不二之选!!
- 本题是一个环状结构,会有很多循环的步骤,从这里开始想:
- 对于点 i ,剩余步数相同的情况下,答案都是一样的;
- 所以用 f 数组表示:第 i 个点,剩下 j 步的情况,减少重复的搜索量;
- 记忆化的f数组,帮助回溯的时候更新;
代码2:记忆化搜索
- 把回溯的内容理解透,才是真正理解递归
//luogu1057:传球游戏:记忆化搜索
// f[i][j]: 第 i 格, 剩余 j 步的 答案
#include<bits/stdc++.h>
int n,m,f[50][50];
void dfs(int x,int t)//当前是 x 位置,走了 t步
{
f[x][t]=0;//初始化当前位置
if(x==1&&t==m) //记忆化1:到达
{
f[x][t]=1;
return ;
}
if(t==m) return ;//剪枝
//搜左边
int a; if(x==1) a=n; else a=x-1;
if(f[a][t+1]==-1) dfs(a,t+1);//左边边界
//搜右边
if(f[x%n+1][t+1]==-1) dfs(x%n+1,t+1);//右边没记录
//回溯更新
f[x][t]=f[a][t+1]+f[x%n+1][t+1];
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%d %d",&n,&m);
dfs(1,0);//从 1 出发,走了 0 步
printf("%d",f[1][0]);
return 0;
}
思路3:DP 分析
-
暴力搜索过不了的题,剪枝可以增加得分量,但如果剩余很多时间(1个小时以上)或者平时练习,还是要掌握相应的DP的思维,多动脑~
-
DP思路: 问什么设什么!
-
f [ i ] [ j ] 表示:第 i 步 走到 j 位置 的方案数,很容易可以想到:任何一个 f[i][j]都是从左和右来的,就是 i-1 步的 j-1和 j+1 位置:
-
所以通式就可以写成:f[i][j]=f[i-1][j-1]+f[i-1][j+1]
-
初始化和边界随便搞一下。
代码3:
- DP代码少,可是你能想到才行~
//luogu1057:传球游戏
//DP思路:
//f[i][j]表示:第 i 步 在 j 位置 的方案数
//任何一个 f[i][j]都是从左和右来的,就是 i-1 步的 j-1和 j+1 位置:
//所以通式就可以写成
//f[i][j]=f[i-1][j-1]+f[i-1][j+1]
#include<bits/stdc++.h>
int n,m;
int f[50][50];
int main()
{
scanf("%d %d",&n,&m);
memset(f,0,sizeof(f));
f[0][1]=1;
for(int i=1;i<=m;i++)//当前第 i 步
{
for(int j=1;j<=n;j++)//当前第 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][n-1]+f[i-1][1];//右边界
else f[i][j]=f[i-1][j-1]+f[i-1][j+1];
}
}
printf("%d",f[m][1]);
return 0;
}
神仙的思路4
- 他是用宽搜+打表+DP的详细分析,如果赛场能按照这样的思路来答题,一定可以最少多拿50分!