版权声明:本文为博主原创文章,未经博主允许不得转载。 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背包板题改一下状态转移方程和初始化条件即可。状态转移 。注意:
- dp数组初始化dp[0]=0,总背包量为0时,邮票数量为0(背包里一张邮票都装不下了)
- 优化函数为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;
}