zcmu1166: 忠哥的dp(II)

题目链接:https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1166

题目大意

n个硬币,面值是ai,每种无限多。然后给你一个s,可以选用多少数量的硬币,使得总面值恰好等于s。输出硬币数量的最小值和最大值。

思路

选物品,数量无限多,那么就是完全背包了。

dp1[i]都表示面值是i的硬币数量。要使得总面值等于j,有两个选择:选当前的a[i],或者不选a[i]。

如果选了a[i],那么就只剩s-a[i],如果dp1[j-a[i]]==inf,或者dp2[j-a[i]]==-1,说明之前的硬币不能凑到j-a[i],反之,则有数量为dp[j-a[i]]+1,这里的1是选的当前硬币。dp1,dp2分别更新最小值和最大值即可。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e4 + 10;
const int inf = 0x3f3f3f3f;
int a[105], dp1[maxn], dp2[maxn];
int main(){
	int n, s;
	while(~scanf("%d%d", &n, &s)){
		for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
		memset(dp1, inf, sizeof(dp1));
		memset(dp2, -1, sizeof(dp2));
		dp1[0] = dp2[0] = 0;
		for(int i = 1; i <= n; i ++){
			for(int j = a[i]; j <= s; j ++){
				if(dp1[j - a[i]] != inf)  
					dp1[j] = min(dp1[j], dp1[j - a[i]] + 1);
				if(dp2[j - a[i]] != -1) 
					dp2[j] = max(dp2[j], dp2[j - a[i]] + 1);
			}
		}
		if(dp1[s] == inf) dp1[s] = -1;
		printf("%d %d\n", dp1[s], dp2[s]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911947/article/details/113092941