Loading

HDU 5527:Too Rich(DFS+贪心)***

题目链接

题意

给出p块钱,现在要用十种硬币凑出,每种硬币有c[i]个,问最多能用多少个硬币。

思路

首先确定,对于每个硬币就是能用小的替换就不用大的。

所以,可以先把硬币尽量用小的替换,如果小的不够用,再用大的去替换。

根据这个思路,就可以处理出一个前 i 个硬币总价值的前缀和 pre[],从大的面额到小面额去枚举,当前这种面额的硬币至少需要使用 (sum - pre[i-1]) / val[i] 种,sum代表当前还剩下多少钱要去兑换,这个数要向上取整,然后继续dfs下去就可以了。

还有一种情况,就是20和50的情况和200和500的情况,即20不能整除50,那么对于p=60,3个20硬币,1个50硬币这种样例就不能去用这种方法解决了。一个比较好的做法就是让这种硬币多用一个,让它的使用数量变成偶数,就可以被整除了。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int N = 15;
int val[] = {0, 1, 5, 10, 20, 50, 100, 200, 500, 1000, 2000};
int c[N], ans, pre[N];

void dfs(int sum, int num, int rem) {
	if(sum < 0) return ;
    if(rem == 0) {
        if(sum == 0) ans = max(ans, num);
        return ;
    }
    int tol = max(sum - pre[rem-1], 0); // 前面的硬币足够的话,就不使用现在的硬币
    int cur = (tol + val[rem] - 1) / val[rem]; // 向上取整
    if(cur <= c[rem]) dfs(sum - cur * val[rem], num + cur, rem - 1);
    cur++; // 当前面整除不了,需要多用一个,变成前面某一个的倍数,例如50和20,500和200
    if(cur <= c[rem]) dfs(sum - cur * val[rem], num + cur, rem - 1);
}

int main() {
	int t; scanf("%d", &t);
	while(t--) {
        int p; scanf("%d", &p);
        pre[0] = 0; ans = -1;
        for(int i = 1; i <= 10; i++)
			scanf("%d", &c[i]), pre[i] = pre[i-1] + c[i] * val[i];
        dfs(p, 0, 10);
        printf("%d\n", ans);
	}
	return 0;
}

posted @ 2017-10-16 14:13  Shadowdsp  阅读(334)  评论(0编辑  收藏  举报