1. 程式人生 > >多重揹包二進位制優化(POJ1276)

多重揹包二進位制優化(POJ1276)

主要是記錄一下對於揹包問題的二進位制優化方法

1.多重揹包使用二進位制優化後轉化為01揹包問題

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <string>
#include <bitset>
#include <map>
#include <cstring>
using namespace std;

int dp[100005];
int main()
{
    int W;
    while(scanf("%d",&W) != EOF)
    {
        memset(dp, 0, sizeof(dp));
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
        {
            int v, c;
            scanf("%d%d", &c, &v);
            int a = 1;
            while(c > a)
            {
                c -= a;
                for(int j = W; j >= a * v; --j)
                    dp[j] = max(dp[j], dp[j - a * v] + a * v);
                a *= 2;
            }
            for(int j = W; j >= c * v; --j)
                dp[j] = max(dp[j], dp[j - c * v] + c * v);
        }
        printf("%d\n", dp[W]);
    }
    return 0;
}

2.多重揹包問題轉化為01揹包和完全揹包問題(看c*v是否超過揹包的容量)

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <string>
#include <bitset>
#include <map>
#include <cstring>
using namespace std;

int dp[100005];
int main()
{
    int W;
    while(scanf("%d",&W) != EOF)
    {
        memset(dp, 0, sizeof(dp));
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
        {
            int v, c;
            scanf("%d%d", &c, &v);
            if(c * v >= W)
            {
                for(int j = v; j <= W; ++j)
                    dp[j] = max(dp[j], dp[j - v] + v);
            }
            else
            {
                int a = 1;
                while(c > a)
                {
                    c -= a;
                    for(int j = W; j >= a * v; --j)
                        dp[j] = max(dp[j], dp[j - a * v] + a * v);
                    a *= 2;
                }
                for(int j = W; j >= c * v; --j)
                    dp[j] = max(dp[j], dp[j - c * v] + c * v);
            }
        }
        printf("%d\n", dp[W]);
    }
    return 0;
}

另外記錄一下另一個同時使用01揹包和完全揹包的寫法

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <set>
#include <algorithm>
typedef long long ll;
using namespace std;
const int N=5e4+7;
int dp[N]={0};
int v;
void com(int w,int p)//完全揹包
{
    for(int j=w;j<=v;j++)
        dp[j]=max(dp[j],dp[j-w]+p);
}
void zero(int w,int p)//01揹包
{
    for(int j=v;j>=w;j--)
        dp[j]=max(dp[j],dp[j-w]+p);
}
void add(int w,int p,int c)
{
    if(c*w>=v)//完全揹包
    {
        com(w,p);
        return ;
    }
    int a=1;
    while(c>a)//01揹包二進位制優化 將數字變為二進位制相加,打包
    {
        c-=a;
        zero(w*a,p*a);
        a*=2;
    }
    zero(w*c,p*c);
}
int main()
{
    int n;
    int w,p,c;
    scanf("%d%d",&n,&v);
    for(int i=0;i<n;i++)
    {
        scanf("%d%d%d",&w,&p,&c);
        add(w,p,c);
    }
    printf("%d\n",dp[v]);
}