• 递归与递推-P1164 小A点菜


    题目背景

    uim神犇拿到了uoira(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种。

    uim指着墙上的价目表(太低级了没有菜单),说:“随便点”。

    题目描述

    不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩MM元(M le 10000)(M10000)。

    餐馆虽低端,但是菜品种类不少,有NN种(N le 100)(N100),第ii种卖a_iai(a_i le 1000)(ai1000)。由于是很低端的餐馆,所以每种菜只有一份。

    小A奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim身上所有钱花完。他想知道有多少种点菜方法。

    由于小A肚子太饿,所以最多只能等待11秒。

    输入格式

    第一行是两个数字,表示NN和MM。

    第二行起NN个正数a_iai(可以有相同的数字,每个数字均在10001000以内)。

    输出格式

    一个正整数,表示点菜方案数,保证答案的范围在intint之内。

    输入输出样例

    输入 #1
    4 4
    1 1 2 2
    
    输出 #1
    3

    代码:(递归实现)
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define MAXN 110
     4 int n, m, ans = 0;
     5 int price[MAXN];
     6 void dfs(int now,int left) {
     7     if (now == n + 1) {
     8         return;
     9     }
    10     if (price[now] <= left) {
    11         if (price[now] == left) {
    12             ans++;
    13         }
    14         dfs(now + 1, left - price[now]);
    15         dfs(now + 1, left);
    16     }
    17     else {
    18         dfs(now + 1, left);
    19     }
    20 }
    21 int main() {
    22     cin >> n >> m;
    23     for (int i = 1; i <= n; i++) {
    24         scanf("%d", &price[i]);
    25     }
    26     dfs(1, m);
    27     printf("%d", ans);
    28     return 0;
    29 }
    动态规划:


      背包问题,dp数组结果是方案数,不妨设dp[i][j]为前i道菜正好花费j元的方案数
      思考当前的方案数(状态)由哪些方案(子状态)转移过来(求递推式的过程)
      1:购买第i种菜品,这种情况下前i-1种菜品需要正好花费j-a[i]元钱,即 dp[i][j]=dp[i-1][j-a[i]]
      2:不购买当前菜品,这种情况下前i-1种菜品需要正好花费j元钱,即 dp[i][j]=dp[i-1][j]
      3:特殊情况:a[i]==j时,第i种菜品直接花掉j元这一种方案 + 前i-1种菜品花掉j元的方案数,即dp[i][j]=dp[i-1][j]+1
      初始化条件:dp数组初始化为0
    代码:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define MAXN 110
     4 int n, m, ans = 0;
     5 int dp[MAXN][10000];
     6 //dp[i][j]:前i种菜品正好花完j块钱时的全部方案数
     7 int a[MAXN];
     8 int main() {
     9     cin >> n >> m;
    10     for (int i = 1; i <= n; i++) {
    11         cin >> a[i];
    12     }
    13     for (int i = 1; i <= n; i++) {
    14         for (int j = 1; j <= m; j++) {
    15             //分情况讨论:
    16             if (a[i] == j) {
    17                 dp[i][j] = dp[i-1][j] + 1;
    18             }
    19             if (a[i] > j) {
    20                 dp[i][j] = dp[i - 1][j];
    21             }
    22             if (a[i] < j) {
    23                 dp[i][j] = dp[i - 1][j] + dp[i - 1][j - a[i]];
    24             }
    25         }
    26     }
    27     cout << dp[n][m];
    28     return 0;
    29 }
    
    
    
    
    
    总结:
      初学动态规划,要理解递归过程与递推过程,递归过程实际上是拆分子问题的过程,如n到n-1的过程,而递推过程是由已知子问题求解父问题的过程。

     动态规划的的四个解题步骤是:

    
    
    • 定义子问题
    • 写出子问题的递推关系
    • 确定 DP 数组的计算顺序
    • 空间优化(可选)
    可参考博客:(31条消息) 图解动态规划的解题四步骤_java牛牛的博客-CSDN博客_动态规划的四个步骤
  • 相关阅读:
    领域驱动设计精简版--阅读笔记
    ATM机的面向对象分析--笔记
    第一部分 Spring 基础
    spring in action 5 笔记--spring 实战 第4版和第5版对比
    Redis深度历险
    《Spring in action》之Spring之旅
    递归算法(java)
    java中static学习总结
    浅谈HookSSDT和和Resume(恢复)SSDT
    转---派遣例程与IRP结构
  • 原文地址:https://www.cnblogs.com/xujiakang123/p/14715748.html
Copyright © 2020-2023  润新知