zoukankan      html  css  js  c++  java
  • 洛谷 p1164 小A点菜 【dp(好题)】 || 【DFS】 【恰好完全装满】

    题目链接:https://www.luogu.org/problemnew/show/P1164

    题目背景

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

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

    题目描述

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

    餐馆虽低端,但是菜品种类不少,有N种(N<=100),第i种卖ai元(ai<=1000)。由于是很低端的餐馆,所以每种菜只有一份。

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

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

    输入格式:

    第一行是两个数字,表示N和M。

    第二行起N个正数ai(可以有相同的数字,每个数字均在1000以内)。

    输出格式:

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

    输入样例#1: 
    4 4
    1 1 2 2
    
    输出样例#1: 
    3

    解题思路:

    这是一道简单的动规题,定义f[i][j]为用前i道菜用光j元钱的办法总数,其状态转移方程如下:

    (1)if(j==第i道菜的价格)f[i][j]=f[i-1][j]+1;

    (2)if(j>第i道菜的价格) f[i][j]=f[i-1][j]+f[i-1][j-第i道菜的价格];

    (3)if(j<第i道菜的价格) f[i][j]=f[i-1][j];

    说的简单一些,这三个方程,每一个都是在吃与不吃之间抉择。若钱充足,办法总数就等于吃这道菜的办法数与不吃这道菜的办法数之和;若不充足,办法总数就只能承袭吃前i-1道菜的办法总数。依次递推,在最后,我们只要输出f[n][m]的值即可。

    dp解法1

    #include <bits/stdc++.h>
    using namespace std;
    int a[101], f[101][10001] = { 0 };
    int main()
    {
        int n, m;
        cin >> n >> m;
        for (int i = 1; i <= n; ++i)cin >> a[i];
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
            {
                if (j == a[i])f[i][j] = f[i - 1][j] + 1;      //如果总钱数j==a[i]的话,也有两种选择,不买或者买(买的可能性只有一种,因为只能买第i件,所以是+1)
                if (j>a[i]) f[i][j] = f[i - 1][j] + f[i - 1][j - a[i]];   //如果总钱数j>a[i]的话,就有两种选择,不买或者买
                if (j<a[i]) f[i][j] = f[i - 1][j];
            }
        cout << f[n][m];
        return 0;
    }
    dp解法2:01背包做法
    #include<iostream>                              
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 10000 + 10;
    int v[maxn], f[maxn];
    int main() {
        int n, m;
        cin >> n >> m;
        f[0] = 1;
        for (int i = 1; i <= n; ++i)
            cin >> v[i];//读入 价值
        for (int i = 1; i <= n; ++i)
            for (int j = m; j >= v[i]; --j)
                f[j] += f[j - v[i]];//现在的花费+=我不点这个菜的时候的花费
        cout << f[m] << endl;        //最后把最后一个点的花费输出来就可以了
            return 0;
    }

    DFS解法

    
    
    #include <cstdio>
    using namespace std;
    int a[101],n,m,sum,b[101];
                   //a[i]表示第i道菜的价格,b[i]表示是否选择了第i道菜 
    void dfs(int k,int x)  //k表示已选的菜的总价格,x表示选到了第几道菜 
    {
        if (k>m) return;  //如果价格已经超过所带的钱数就退出 
        if (k==m)  //价格正好 
        {
            sum++;  //计数 
            return;  //返回 
        }
        for (int i=x+1;i<=n;i++)  //因为选到了第x道菜,所以从第x+1道菜开始选 
         if (b[i]==0)  //如果没选过这道菜 
         {
             b[i]=1;  //选择这道菜 
             dfs(k+a[i],i);  //价格加上这道菜的价格,选到了第i道菜 
             b[i]=0;  //不选择这道菜 
         }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
         scanf("%d",&a[i]);
        dfs(0,0);  //一开始没选菜,总价为0,选到了第0道菜 
        printf("%d
    ",sum);
        return 0;
    }
    
    

    2018-05-15

  • 相关阅读:
    121.买卖股票 求最大收益1 Best Time to Buy and Sell Stock
    409.求最长回文串的长度 LongestPalindrome
    202.快乐数 Happy Number
    459.(KMP)求字符串是否由模式重复构成 Repeated Substring Pattern
    326.是否为3的平方根 IsPowerOfThree
    231.是否为2的平方根 IsPowerOfTwo
    461.求两个数字转成二进制后的“汉明距离” Hamming Distance
    206.反转单链表 Reverse Linked List
    448. 数组中缺少的元素 Find All Numbers Disappeared in an Array
    常见表单元素处理
  • 原文地址:https://www.cnblogs.com/00isok/p/9042939.html
Copyright © 2011-2022 走看看