01背包 ZOJ 3931 Exact Compression

 

题目连接

题意:n个数字构建哈夫曼树,问是否存在这样一棵树使得:(Fi数字大小,Ci哈夫曼表示下,'0'的数量)

分析:每次从优先队列取出两个数字可以互换位置,这样可以01互换。设a[i] <= b[i],a[i]为左儿子,b[i]为右儿子,如果加上a[i],表示累加上了a[i]下的所有点在i的位置的0的贡献,如果加上b[i]-a[i]就表示左右互换。所以可以转换为01背包问题换不换的问题,考虑到E很大,初始化为E’=E-,表示从最小的可能值到所求E的累加值E',然后对E‘进行dp

#include <bits/stdc++.h>

const int S = 128 + 5;
const int N = 128000 + 5;
int a[S], b[S];
int dp[N];

int main() {
    int T; scanf ("%d", &T);
    while (T--) {
        int n; scanf ("%d", &n);
        std::priority_queue<int, std::vector<int>, std::greater<int> > pque;
        for (int x, i=0; i<n; ++i) {
            scanf ("%d", &x);
            pque.push (x);
        }
        int E, sum = 0; scanf ("%d", &E);
        for (int i=1; i<n; ++i) {
            int fir = pque.top (); pque.pop ();
            int sec = pque.top (); pque.pop ();
            if (fir > sec) {
                std::swap (fir, sec);
            }
            a[i] = fir; b[i] = sec;
            E -= a[i]; sum += b[i] - a[i];
            pque.push (fir + sec);
        }
        if (E < 0 || E > sum) {
            puts ("No");
            continue;
        }
        std::fill (dp, dp+1+E, 0);
        dp[0] = 1;
        for (int i=1; i<n; ++i) {
            int dif = b[i] - a[i];
            for (int j=E; j>=dif; --j) {
                if (dp[j-dif]) {
                    dp[j] = 1;
                }
            }
        }
        if (dp[E]) {
            puts ("Yes");
        } else {
            puts ("No");
        }
    }

    return 0;
}

还有bitset的暴力写法,<< 运算相当于加,参考博文

posted @ 2016-04-14 19:12  Running_Time  阅读(326)  评论(0编辑  收藏  举报