问题描述
话说大诗人李白, 一生好饮。幸好他从不开车。
一天, 他提着酒显, 从家里出来, 酒显中有酒 2 斗。他边走边唱:
无事街上走,提显去打酒。 逢店加一倍, 遇花喝一斗。
这一路上, 他一共遇到店 N 次, 遇到花 M 次。已知最后一次遇到的是花, 他正好把酒喝光了。
请你计算李白这一路遇到店和花的顺序, 有多少种不同的可能?
注意: 显里没酒 ( 0 斗) 时遇店是合法的, 加倍后还是没酒; 但是没酒时遇 花是不合法的。
输入格式
第一行包含两个整数 N 和 M.
输出格式
输出一个整数表示答案。由于答案可能很大,输出模 1000000007 的结果.
样例输入
5 10
样例输出
14
样例说明
如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:
010101101000000
010110010010000
011000110010000
100010110010000
011001000110000
100011000110000
100100010110000
010110100000100
011001001000100
100011001000100
100100011000100
011010000010100
100100100010100
101000001010100
评测用例规模与约定
对于 40% 的评测用例: 1≤N,M≤10 。
对于 100% 的评测用例: 1≤N,M≤100 。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
int arr[101][101][101];
ll dfs(int n,int m,int a){
ll out=0;
if(a==0){
if(m==0&&n==0){
return 1;
}
return 0;
}
if(a<0||a>m||m==0||n>=m&&a>0){
return 0;
}
if(n==0)
return m==a;
if(arr[n][m][a]!=-1){
return arr[n][m][a];
}
out=dfs(n-1,m,a*2)+dfs(n,m-1,a-1);
out%=mod;
arr[n][m][a]=out;
return out;
}
int main(){
memset (arr,-1,sizeof arr);
int n,m;
cin>>n>>m;
cout<<dfs(n,m,2);
}
这道题是一道典型的深度+记忆化搜索,再用剪枝优化 ,思路还是比较清晰的,看一个大佬说dp也能写,在这大概捋一下思路:应该是从底层向上搜索吧,(规定最后一次是花)从arrr[0][1][1]到arr[N][M][2],每次向arr[n+1][m][now/2] 和 arr[n][m+1][now+1]这两个方向发展,然后就没有然后了【苦笑】,如果这么想的话就太麻烦了,要考虑的细节太多,我觉得是写不出来了。
然后搜了一下:分析:这是一道动态规划题,设f[i][j][k]表示走到了第i个位置,遇到了j个花,还剩k斗酒的合法方案数,初始化很简单就是f[0][0][2]=1,因为一开始酒的数量是2,假如共遇到店n次,遇到花m次:那么答案就是f[n+m-1][m-1][1],这是很容易理解的,因为我们共需要遇到m次花且最后一次一定是花,则走到倒数第二个位置时一定已经遇到了m-1个花,且由于遇到花后酒的数量会减少1,所以走到倒数第二个位置时酒的数量也必须是1。原文链接https://blog.csdn.net/AC__dream/article/details/124072351(这个思路才是可行的,只能说我还是太菜了,一起学习一下吧)