HDU - 2844 - コイン(複数のバックパックバイナリ最適化)

リンクタイトル
タイトル効果:コインの異なる金種のいくつかの部分の所定のいくつかの組み合わせ、これらのコインでは、範囲は1〜mが異なる宗派の多くの種類で構成することができる要求します。
  表面には、複数のバックパックの非常に典型的な問題ですが、データは直接オフマルチバックパックを使用することはできていないようです。バイナリの最適化:それはバックパックの最適化技術の倍数でなければなりません。我々は数値を入れる(N- \)\に分割され(1,2,4,8 ... \)\\(K \) 残りの分割数)が間隔で発現させることができるN、1 - [(\ ] \)の数内のすべて。なぜ?前述の数を超えることとバイナリに等しくなければならないので\(K \) 場合\(K \)は、彼らが大きく進数のうちリッピングすることができる場合よりも大きいです。それ以来、2進数の前に発現させることができる([1、NK] \ \ ) (バイナリ角度を理解することができる)で数、プラス\(Kは\)に表すことができる([1、N] \ \)の数インチ
  だから、長い間私たちの以前の記事の最初のいくつかの前処理を行うよう。それはお金の合計値以上である場合、単一の項目については、直接リスト上のアイテムとの完全なバックパックとして、単語の数を持っています。数は少ない独自のお金の合計値よりも、バイナリ最適化でそれを入れている場合に実行する項目の数に分割され、\(01 \)バックパック。最後に、異なる宗派の統計は、すべての項目は、行の数を作ることができます。

const int maxn = 1e5+10;
int coin[105], c[105];
bool dp[maxn];
int main(void) {
    int n, m;
    while(~scanf("%d%d", &n, &m) && (n||m)) {
        zero(dp); dp[0] = 1;
        for (int i = 1; i<=n; ++i) scanf("%d", &coin[i]);
        for (int i = 1; i<=n; ++i) {
            scanf("%d", &c[i]);
            if (coin[i]*c[i]>=m)
                for (int k = coin[i]; k<=m; ++k) //完全背包
                    dp[k] |= dp[k-coin[i]];
            else {
                for (int j = 1; c[i]>=j; j<<=1) { //对多重背包进行二进制优化
                    for (int k = m; k>=coin[i]*j; --k)
                        dp[k] |= dp[k-coin[i]*j];
                    c[i]-=j;
                }
                if (c[i]) 
                    for (int k = m; k>=coin[i]*c[i]; --k)
                        dp[k] |= dp[k-coin[i]*c[i]];
            }
        }
        int sum = 0;
        for (int i = 1; i<=m; ++i) sum += dp[i];
        printf("%d\n", sum);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/shuitiangong/p/12660977.html