2017acm香港区域赛 Optimal Coin Change(完全背包+记录路径)

题目:

用几种面额的钱凑一个面额,问最少需要多少枚硬币。数量相同时尽量使用小面额,输出每个硬币用多少枚。输入的硬币已经按面额小到大排好序。

分析:

完全背包+路径输出。
因为要尽可能使用小面额的硬币,所以在转移的时候:

  • 如果 f[j-a[i]] + 1 < f[j],肯定是要转移,记录状态j用的i硬币转移来的。
  • 如果 f[j-a[i]] + 1 = f[j],也要转移,因为f[j]不变的情况下,越往后硬币 i 面额越大,那也就意味着前面用了更小的面额。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=2050;
const double EPS=1e-8;
const int INF=0x3f3f3f3f;
const int MOD = 1e9+7;
int f[MAXN],n,V,a[MAXN],num[MAXN],pre[MAXN];
int main(){
	// freopen("1.txt","r",stdin);
	ios::sync_with_stdio(false);
	while(cin >> V >> n){
		for(int i=1;i<=n;i++){
			cin >> a[i];
		}
		ms(num,0);
		f[0] = 0;
		pre[0] = 0;
		for(int i=1;i<=V;i++)	f[i] = INF;
		for(int i=1;i<=n;i++){
			for(int j=a[i];j<=V;j++){
				// f[j] = min(f[j], f[j-a[i]]+1);
				if(f[j-a[i]] + 1 <= f[j]){
					f[j] = f[j-a[i]]+1;
					pre[j] = i;
				}
			}
		}
		if(f[V] == INF) cout << "-1\n";
		else{
			while(V){
				num[pre[V]]++;
				V -= a[pre[V]];
			}
			for(int i=1;i<=n;i++){
				cout << num[i] << " \n"[i==n];
			}
		} 
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值