深圳幻海软件技术有限公司 欢迎您!

2039: [蓝桥杯2022初赛] 李白打酒加强版 (动态规划)

2023-04-17

 题目描述话说大诗人李白,一生好饮。幸好他从不开车。一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:无事街上走,提壶去打酒。逢店加一倍,遇花喝一斗。这一路上,他一共遇到店N次,遇到花M次。已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白这一路遇到店和花的顺序,有多少种不同的

 

题目描述

话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒 2 斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店 N 次,遇到花 M 次。
已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?
注意:壶里没酒( 0 斗) 时遇店是合法的,加倍后还是没酒;但是没酒时遇花是不合法的。

输入格式

输入包含多组测试数据。
第一行为T,表示存在T组测试数据,T不超过30。
对于每组测试数据,输入两个整数N 和M.
1 ≤ N, M ≤ 100。

输出格式

输出一个整数表示答案。由于答案可能很大,输出模1000000007 的结果。

输入样例 复制

  1. 1
  2. 5 10

输出样例 复制

14

最开始是没写出来的,想的是深度优先搜索,也就是第二个代码,不能AC,后面看别人的推荐,才知道闫学灿(y总)(acwing网站的创始人,开了很多课,我相信有必要去看一看,慢慢的把数据结构学了,也得准备CCF的CSP认证了),看了他讲的蓝桥杯初赛,才搞懂了,从侧面也能看出,我很弱,emm,确实,革命尚未成功,我得继续努力。

分析:

状态设计:dp[i][j][k]的值表示遇到i家店,j朵花,酒壶中还剩k斗酒的可能情况数;
    状态转移方程:dp[i][j][k]=dp[i-1][j][k/2](i>1&&k%2==0) + dp[i][j-1][k+1](j>1);
    边界设计:除了dp[0][0][2]=1,其他元素全为0;
    他一共遇到店 N 次,遇到花 M 次。已知最后一次遇到的是花, 他正好把酒喝光了;所以
    最后一次肯定遇到的是花,那么最后的结果便是dp[N][M-1][1];
    并且酒壶中酒的容量不能超过M;

  1. /**
  2. 再编码:
  3. 状态设计:dp[i][j][k]的值表示遇到i家店,j朵花,酒壶中还剩k斗酒的可能情况数;
  4. 状态转移方程:dp[i][j][k]=dp[i-1][j][k/2](i>1&&k%2==0) + dp[i][j-1][k+1](j>1);
  5. 边界设计:除了dp[0][0][2]=1,其他元素全为0
  6. 他一共遇到店 N 次,遇到花 M 次。已知最后一次遇到的是花, 他正好把酒喝光了;所以
  7. 最后一次肯定遇到的是花,那么最后的结果便是dp[N][M-1][1];
  8. 并且酒壶中酒的容量不能超过M;
  9. */
  10. #include <cstdio>
  11. #include <cstring>
  12. using namespace std;
  13. const int mod=1000000007;
  14. int main()
  15. {
  16. int T;
  17. scanf("%d",&T);
  18. while(T--)
  19. {
  20. int n,m;
  21. scanf("%d%d",&n,&m);
  22. int dp[n+1][m+1][m+1];
  23. memset(**dp,0,sizeof(dp));
  24. dp[0][0][2]=1;
  25. for(int i=0;i<=n;++i)
  26. for(int j=0;j<=m;++j)
  27. for(int k=0;k<=m;++k)
  28. {
  29. int &val=dp[i][j][k];
  30. if(i>=1&&k%2==0)
  31. val=(val+dp[i-1][j][k/2])%mod;
  32. if(j>=1)
  33. val=(val+dp[i][j-1][k+1])%mod;
  34. }
  35. printf("%d\n",dp[n][m-1][1]);
  36. }
  37. return 0;
  38. }

 DFS解决
    只能AC 13%,不得不说,对于一个问题,不能找到正确的算法策略与正确的算法策略
    比较,可谓是天壤之别;

  1. /**
  2. DFS解决
  3. 只能AC 13%,不得不说,对于一个问题,不能找到正确的算法策略与正确的算法策略
  4. 比较,可谓是天壤之别;
  5. */
  6. #include <iostream>
  7. #include <cstdio>
  8. using namespace std;
  9. const int mod=1000000007;
  10. void drink_DFS(int store,int flow,int drink);
  11. int sum=0,N,M;
  12. int main()
  13. {
  14. int T;
  15. scanf("%d",&T);
  16. while(T--)
  17. {
  18. sum=0;
  19. scanf("%d%d",&N,&M);
  20. drink_DFS(0,0,2);
  21. printf("%d\n",sum);
  22. }
  23. return 0;
  24. }
  25. void drink_DFS(int store,int flow,int drink)
  26. {
  27. if(drink < 0) return;
  28. if(store > N || flow >= M) return;
  29. if(drink>M) return;
  30. if(store==N&&flow==M-1&&drink==1)
  31. {
  32. sum+=1;
  33. sum%=mod;
  34. return;
  35. }
  36. drink_DFS(store+1,flow,2*drink);
  37. drink_DFS(store,flow+1,drink-1);
  38. // store+=1;
  39. // drink*=2;
  40. // drink_DFS(store,flow,drink);
  41. // store-=1;
  42. // drink/=2;
  43. // flow+=1;
  44. // drink-=1;
  45. // drink_DFS(store,flow,drink);
  46. // flow-=1;
  47. // drink+=1;
  48. }

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览44229 人正在系统学习中