背包组题

完全背包

Dollars

UVa 147
给出100元、50元、20元、10元、5元、2元,1元、50分、20分、10分和5分共11种dollars,求组成所给价格的方法数。
每种dollar都有无限多,故为一个完全背包,先离线把表打出来,之后在线查询即可。
滚动数组实现。

#include <bits/stdc++.h>

#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1e5 + 10;
int n, m;
ll dp[N],;
int b[]={1,2,4,10,20,40,100,200,400,1000,2000};
inline void init(){
    for(int i=0;i<=6000;i++) dp[i]=1;
    for(int i=1;i<11;i++)
        for(int j=b[i];j<=6000;j++)
             dp[j]+=dp[j-b[i]];
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    init();
    double money;
    while(cin>>money){
        if(money<1e-2) break;
        int n=money*20;
        printf("%6.2lf%17lld\n",money,dp[n]);
    }
    return 0;
}

Dollar Dayz

POJ 3181
1k1-k有无限多,求其凑出nn的方法数。
会爆longlonglong long,用大数,或者将超出的高位数单独记下,最后一起输出。

int main(){
    int n,k;
    cin >> n >> k;
    BigNum dp[1010];
    dp[0]=1;
    for (int i = 1; i <= k; i++) {
        for (int j = i; j <= n; j++) {
            dp[j] = dp[j] + dp[j-i];
        }
    }
    cout << dp[n] << endl;
    /*   
    ll dp[N][N];
    for (int i = 0; i <= n; i++) dp[i][0] = 1;
    for (int i = 1; i <= k; i++) {
    	if(j>=i) 
    		dp[i][j] = dp[i - 1][j] + dp[i][j - i];
    	else dp[i][j] = dp[i - 1][j];           
    }
    */
    return 0;
}

Piggy-Bank

POJ 1384
硬币无限,求容量下最小的价值。
完全背包。

#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1e4 + 10;
int v[N], w[N];
int dp[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin >> T;
    while (T--) {
        int e, f, n, m;
        cin >> e >> f;
        m = f - e;
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> v[i] >> w[i];
        memset(dp, inf, sizeof dp);
        dp[0] = 0;
        for (int i = 1; i <= n; i++)
            for (int j = w[i]; j <= m; j++)
                dp[j] = min(dp[j], dp[j - w[i]] + v[i]);
        if (dp[m] == inf)
            cout << "This is impossible.\n";
        else
            cout << "The minimum amount of money in the piggy-bank is " << dp[m] << ".\n";
    }
    return 0;
}

01背包

Charm Bracelet

POJ 3624
裸包,注意01背包和完全背包不同,需要倒序枚举容量即可。
滚动数组实现。

#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1e5 + 10;
int n, m;
int dp[N], w[N], v[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    while (scanf("%d%d",&n,&m)!=EOF) {
        for (int i = 0; i <= m; i++) dp[i] = 0;
        for (int i = 1; i <= n; i++)
            scanf("%d %d", &w[i], &v[i]);
        for (int i = 1; i <= n; i++)
            for (int j = m; j >= w[i]; j--)
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
        printf("%d\n", dp[m]);
    }
    return 0;
}

多重背包

Space Elevator

POJ 2392
nn种不同类型的块,第ii类块的数量为cic_i,每个块的高度hih_i,允许这种类型的块达到的最高高度为aia_i,求将这些块组合能达到的最高高度。
aia_i为关键字排序,这样就能使得塔的高度最大;
排序后按多重背包算法计算每一个塔高的可行性:设dp[k]dp[k]为建造高度kk的塔的可行性,则dp[k]=dp[k]dp[kblocks[i].hi]dp[k]=dp[k]|dp[k-blocks[i].hi]其中0in1jblocks[i].ciblocks[i].a&lt;=k&lt;=blocks[i].hi0≤i≤n,1≤j≤blocks[i].ci,blocks[i].a&lt;=k&lt;=blocks[i].hi最后,按照可能塔高的递减顺序搜索{dpn}\{dp_n\},第一个dp[i]=1的塔高i即为塔的最大高度。

//贪心 + 可行性多重背包
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N = 4e2 + 10;
typedef std::pair<int, int> pii;
int h[N], a[N], c[N];
struct node {
    int h, a, c;
    bool operator<(const node &rhs) const {
        return a < rhs.a;
    }
} blocks[N];
int dp[1 << 16], k;

int main() {
    while (cin >> k) {
        for (int i = 0; i < k; i++)
            scanf("%d %d %d", &blocks[i].h, &blocks[i].a, &blocks[i].c);
        sort(blocks, blocks + k);
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        for (int i = 0; i < k; i++)
            for (int j = 0; j < blocks[i].c; j++)
                for (int z = blocks[i].a; z >= blocks[i].h; z--)
                    dp[z] |= dp[z - blocks[i].h];

        for (int i = blocks[k - 1].a; i >= 0; i--)
            if (dp[i]) {
                cout << i << endl;
                break;
            }
    }
    return 0;
}
posted @ 2019-08-02 23:37  Mr.doublerun  阅读(16)  评论(0)    收藏  举报