01背包 ZOJ 3931 Exact Compression

时间:2023-03-08 20:54:22

题目连接

题意:n个数字构建哈夫曼树,问是否存在这样一棵树使得:01背包 ZOJ 3931 Exact Compression(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-01背包 ZOJ 3931 Exact Compression,表示从最小的可能值到所求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的暴力写法,<< 运算相当于加,参考博文