动态规划--多重背包--hdu2844 coins

来源:互联网 发布:windows arp欺骗工具 编辑:程序博客网 时间:2024/06/08 09:09

01背包:每种物体只有1个,可选择取或不取

完全背包:每种物体有无数个(当每种物体 重量w * 个数 c >= 背包容量 V 时,可视为完全背包)

多重背包:每种物体有c[ i ]个

将个数c拆分成1,2,4,...,2^(k - 1),c - (2 ^ k - 1)

拆分为二进制则可表示1到c任意的数字。

while ( int x) //x为该种物品的总个数

{

int t = 1;

while (x >= t)

{

v[ cnt ] = t *  per_v;// 价格

w[ cnt ++] = t * per_b;//重量

x -= t;

t <<= 1;

}

if ( x )

{

v[ cnt ] = x * per_v;

w[ cnt ++] = x * per_w;

}

hdu2844

有n种硬币,面值为a [ i ],个数为c [ i ].手表最多m元,求硬币最多能表示多少种价格(1..m)

背包容量m。多重背包。每种硬币的重量(费用)、价值均为a [ i ]。

转化为01背包后,

 for i = 1 to cnt

for j = m to a[ i ]

f [ j ] = max( f [ j ] , f [ j - a [ i ]] + a [ i ] );

最后的 f [ j ]即为考虑了所有的硬币后,当背包的容量为j时的最大价值。

因为背包容量即想要凑出的钱,for i = 1 to m,当f [ i ] = i 时,即所有硬币可凑出价格i,计数 +1。


#include <iostream>

#include <cstdio>

#include <vector>

#include <set>

#include <cstring>

using namespace std;

const int maxn = 105;

const int maxm = 1e5 + 5;

int a[maxn],b[maxn];

int f[maxm];

vector<int> v;

void change(int x,int per)

{

    int t = 1;

    while(x >= t)

    {

        v.push_back(t * per);

        x -= t;

        t <<= 1;

    }

    if (x) {

        v.push_back(x * per);

    }

}

int main()

{

    int n,m;

    while(scanf("%d%d",&n,&m) != EOF)

    {

        if (n == 0 && m == 0) {

            return 0;

        }

        v.clear();

        memset(f0sizeof(f));

        int ans = 0;

        for (int i = 0; i < n; i ++) {

            scanf("%d",&a[i]);

        }

        for (int i = 0; i < n; i ++) {

            scanf("%d",&b[i]);

            change(b[i],a[i]);

        }

        for (int i = 0; i < v.size(); i ++) {

            for (int j = m; j >= v[i]; j --) {

                f[j] = max(f[j] ,f[j - v[i]] + v[i] ) ;

            }

        }

        for (int i = 1; i <= m; i ++) {

            if (f[i] == i) {

                ans ++;

            }

        }

        printf("%d\n",ans);

    }

    return 0;

}


原创粉丝点击