牛客网 最小邮票数(01背包变形、清华机试)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sunlanchang/article/details/88554487

题目描述

有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有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

Description

01背包板题改一下状态转移方程和初始化条件即可。状态转移 d p [ i ] = m i n ( d p [ i ] , d p [ i w e i g h t [ j ] ] + 1 ) , j , i dp[i]=min(dp[i],dp[i-weight[j]]+1),j为邮票面值,i为遍历给定的总价值 。注意:

  1. dp数组初始化dp[0]=0,总背包量为0时,邮票数量为0(背包里一张邮票都装不下了)
  2. 优化函数为min时,dp除了首元素其余元素初始化为INF。优化函数为max时,dp除了首元素其余初始化为0。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1111;
const int INF = 0x3f3f3f3f;
int dp[maxn];          //代表总值为maxn时最少需要多少张邮票
int total_vol, number; //总值、给定的邮票数量
struct Obj
{
    int weight; //weight为邮票的面值3分、5分等
};
Obj arr[maxn];
void init()
{
    memset(dp, 0x3f, sizeof(dp));
    for (int i = 0; i < maxn; i++)
        arr[i].weight = 0;
}
int main()
{
    // freopen("input.txt", "r", stdin);
    while (~scanf("%d%d", &total_vol, &number))
    {
        init();
        for (int i = 1; i <= number; i++)
            scanf("%d", &arr[i].weight);
        // 遍历所有物品
        dp[0] = 0; //初始化dp[0]:当总值是0时,需要0张邮票
        for (int i = 1; i <= number; i++)
        {
            // 背包从总重量递减,直至与物品重量相等放不下该物品为止
            // 倒序更新d[j],小于arr[i]物品重量的dp值不变
            for (int j = total_vol; j >= arr[i].weight; j--)
                dp[j] = min(dp[j], dp[j - arr[i].weight] + 1); //状态转移用min,注意与01背包的max的不同
        }
        if (dp[total_vol] != INF)
            printf("%d\n", dp[total_vol]);
        else
            printf("0\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunlanchang/article/details/88554487