hdu3591 The trouble of Xiaoqian [多重背包 + 完全背包 + 01背包]

版权声明:转载请声明出处!!!https://blog.csdn.net/anthony1314 https://blog.csdn.net/anthony1314/article/details/88380712

题意:

消费者有n种硬币,每种硬币的价值为v[i], 数量为c[i],而超市有消费者拥有的每一种硬币,且每种有无限个,每次去买东西, 如果要找钱的话, 超市会给你最少的硬币数, 给你一个数t,要你求出,最少需要用到的硬币数量在本次交易中(消费者需要携带的硬币数量 + 超市找钱给的硬币数量)。(t<= 20000)

题解:

对超市进行完全背包

对消费者进行多重背包

加入消费者的某种硬币的总价值大于最大值,那么可以进行对其完全背包

/*
Algorithm: 完全背包 + 多重背包
Author: anthony1314
Creat Time:
Time Complexity:
*/

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cstring>
#include<cstdio>
//#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define mod 1e9 + 7
#define line printf("--------------");
using namespace std;
#define inf 0x3f3f3f3f
#define mm 20005
#define maxn 105
int v[maxn], c[maxn];
int dp1[mm], dp2[mm];
int n, t;
void zero_one_bag(int *dp, int vv, int cc) { // vv代表价值  cc代表硬币数量
    for(int i = 20000; i >= vv; i--) { //逆序
        dp[i] = min(dp[i-vv] + cc, dp[i]);
    }
}
void com_bag(int *dp, int vv) {//完全背包
    for(int i = vv; i <= 20000; i++) {//正序
        dp[i] = min(dp[i], dp[i-vv] + 1);//每次加1
    }
}
void many_bag(int *dp, int vv, int cc) {//多重背包
    if(vv * cc >= 20000) {//总价值超过最大可以直接完全背包
        com_bag(dp, vv);
        return ;
    }
    int k = 1;
    while(k < cc) {//多重背包 2进制优化 
        zero_one_bag(dp, vv*k, k);
        cc -= k;
        k *= 2;
    }
    zero_one_bag(dp, vv*cc, cc);
}
int main() {
    int ccc = 1;
    while(cin>>n>>t) {
        if(n == 0 && t == 0) {
            break;
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &v[i]);
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &c[i]);
        }

        memset(dp1, inf, sizeof(dp1));
        memset(dp2, inf, sizeof(dp2));
        dp1[0] = dp2[0] = 0;
        for(int i = 1; i <= n; i++) {
            many_bag(dp1, v[i], c[i]);
        }
        for(int i = 1; i <= n; i++){
            com_bag(dp2, v[i]);
        }
        int ans = dp1[t];
        for(int i = t+1; i <= 20000; i++){
            ans = min(ans, dp1[i] + dp2[i-t]);
        }
        printf("Case %d: ", ccc++);
        if(ans == inf){
            cout<<"-1"<<endl;
            continue;
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/anthony1314/article/details/88380712