二進制優化DP Hdu1059-Diving

多重揹包的複雜度爲O(n * m * k),其中n爲揹包總容量,m爲物品種類數,k爲一種物品的數量。實際上等價於01揹包。
二進制優化,是將一種物品的數量分解成1, 2, 4, 8, …, 2x, k-2x+1+1份並組成新的物品,注意除了最後一個數,其他數都是2的冪次。此時選擇任意數量的該原物品,都可以等價表示成選擇分解後的某幾個新物品。選擇新物品的任意組合,都可以表示成選擇一定數量的原物品。於是轉化爲物品數目m * log2klog_2k的01揹包。因此複雜度爲O(n * m * log2klog_2k)。

題意

6種物品,權重爲1到6,給出數量。求是否可能均分爲兩份權重相同的?

分析

顯然這是一個多重揹包,總容量是總權重值,物品容量是其權重。求dp[n/2]是否有解。普通多重揹包會TLE,所以要用二進制優化,將6種物品分解成新的物品,轉化爲01揹包

代碼

// 二進制優化多重揹包
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 20000;
bool dp[6*MAX_N+1];
int vals[6*MAX_N+1];
int main()
{
    int n[7];
    int k = 0;
    while (++k)
    {
        int sum = 0;
        int cnt = 0;
        for (int i = 1; i <= 6; i++)
        {
            scanf("%d", &n[i]);
            sum += i * n[i];
            // 將num個同類型物品捆綁爲一個新物品
            // 可以用新物品的組合表示任意數量的原物品
            int num = 1;
            while (num <= n[i])
            {
                vals[cnt++] = num*i;
                n[i] -= num;
                num *= 2;
            }
            if (n[i] > 0) vals[cnt++] = i*n[i];
        }
        // 轉化爲01揹包
        if (sum == 0) break;
        memset(dp, 0, sizeof(dp));
        dp[0] = true;
        for (int i = 0; i < cnt; i++)
            for (int j = sum; j >= vals[i]; j--)
                dp[j] |= dp[j-vals[i]];
        printf("Collection #%d:\n", k);
        if (sum % 2 == 0 && dp[sum/2] == true)
            printf("Can be divided.\n\n");
        else 
            printf("Can't be divided.\n\n");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章