• 清华机试-最小邮票数


    题目描述

        有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。     如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。

    输入描述:

        有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈 20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。

    输出描述:

          对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。

    示例1

    输入

    10

    5

    1 3 3 3 4

    输出

    3

    解题思路

    一开始看到这个题目,想到的是bfs。bfs的思路是:枚举所有的可能性,最多有2的19次方种情况(524288种)。可以从0列到524287,一个数的二进制形式表示选或者不选这张邮票。由于对于每一个数字最多要列举19位,所以时间复杂度大约是O(19*2^19)。比较高但是应该也是可以通过的,因为其实有一些数字不用列举那么多位。

    后来想到可以用动态规划来解决这个问题。如果将状态dp[i][j]定义为前i张邮票凑成总值j所需要的最少邮票数。则状态可以初始化为dp[i][0]=0。(其中,1<=i<N,0<=j<M)。

    状态转移方程如下:

    dp[i][j] = min(dp[i-1][j],dp[i-1][j-v[i]])。(其中,i>0,j-v[i]>=0)

    同时注意判断dp[i][j]是否等于-1。-1表示dp[i][j]无解。

    代码

    #include <iostream>
    
    #include <cmath>
    
    using namespace std;
    
    int dp[20][100] = {-1};
    
    int num[20];
    
    int main()
    
    {
    
        cout << pow(2,19) * 19 << endl;
    
        int m,n;
    
        while(cin >> m >> n)
    
        {
    
            int ans = 20;
    
            for(int i = 0;i < n;i++)
    
            {
    
                dp[i][0] = 0;
    
                for(int j = 1;j <= m;j++)
    
                    dp[i][j] = -1;
    
            }
    
            for(int i = 0;i < n;i++)
    
                cin >> num[i];
    
            for(int i = 0;i < n;i++)
    
            {
    
                for(int j = num[i];j <= m;j++)
    
                {
    
                    if(i == 0)
    
                    {
    
                        if(j == num[i]) dp[i][j] = 1;
    
                        else dp[i][j] = -1;
    
                    }
    
                    else
    
                    {
    
                        int a = 20;
    
                        if(dp[i - 1][j - num[i]] != -1)
    
                            a = dp[i - 1][j - num[i]] + 1;
    
                        int b = 20;
    
                        if(dp[i - 1][j] != -1)
    
                            b = dp[i - 1][j];
    
                        int c = min(a,b);
    
                        if(c == 20) dp[i][j] = -1;
    
                        else dp[i][j] = c;
    
                    }
    
                }
    
            }
    
            if(dp[n - 1][m] == -1) cout << 0 << endl;
    
            else cout << dp[n - 1][m] << endl;
    
        }
    
        return 0;
    
    }
    

      

  • 相关阅读:
    java
    java
    Java hashCode() 和 equals()
    Python可变参数*和**
    Hadoop Mapreduce分区、分组、二次排序
    Java 内部类
    java valueOf()函数
    java接口和抽象类
    Java instanceof运算符
    JAVA ==号和equals()的区别
  • 原文地址:https://www.cnblogs.com/tracy520/p/8836340.html
Copyright © 2020-2023  润新知