給定n種硬幣,其中第 i 種硬幣的面值為ai,共有ci個。
從中選出若干個硬幣,把面值相加,若結果為s,則稱「面值s能被拼成」。
求1~m之間能被拼成的面值有多少個。
輸入包含多組測試用例。
每組測試用例第一行包含兩個整數n和m。
第二行包含2n個整數,分別表示a1,a2,…,an和c1,c2,…,cn。
當輸入用例n=0,m=0時,表示輸入終止,且該用例無需處理。
每組用例輸出乙個結果,每個結果佔一行。
1≤n≤100,
1≤m≤105,
1≤ai≤105,
1≤ci≤1000
3 10
1 2 4 2 1 1
2 51 4 2 1
0 0
8
4
先不看題
對於多重揹包, 可以拆成01揹包來做
unsigned int f[maxn];
memset(f, 0, sizeof f);
f[0] = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= c[i]; ++j)
for (int k = m; k >= v[i]; --k)
f[k] = max(f[k], f[k - v[i]] + w[i]);
int ans = 0;
for (int i = 0; i <= m; ++i)
ans = max(maxn, f[i]);
\(c_i\)拆成p + 2個物品
\(2^0\) * \(v_i\), \(2^1\) * \(v_i\), ... , \(2^p\) * \(v_i\), \(r_i\) * \(v_i\)
雖然沒佇列優化快,但是好寫
unsigned int f[maxn];
int nw[maxn * log2(maxn)], nv[maxn * log2(maxn)];
int cnt = 0;
for (int i = 1; i <= n; ++i)
if (s[i]) nw[++cnt] = s[i] * w[i], nv[cnt] = s[i] * v[i];
}memset(f, 0, sizeof f);
for (int i = 1; i <= cnt; ++i)
for (int j = m; j >= nv[i]; --j)
f[j] = max(f[j], f[j - nv[i]] + nw[i]);
#include using namespace std;
const int maxn = 2005;
int n, v[maxn], w[maxn], c[maxn], q[maxn], m, f[maxn];
int calc(int u, int i, int k)
int main()
for (int p = maxp; p; --p)}}
}int ans = 0;
for (int i = 1; i <= m; ++ i) ans = max(ans, f[i]);
printf("%d", ans);
return 0;
}
好了來看題, 一定要注意到我們只關注可行性,而不關注最優解
暴力01揹包
bool f[maxn];
memset(f, 0, sizeof);
f[0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= c[i]; ++j)
for (int k = m; k >= a[i]; --k)
f[k] |= f[k - a[i]];
必定超時, 但是這道題是可行性為題, 不需要最優解
我們發現,若前i種硬幣能湊出 sum/2, 只有兩種情況:
1.在i階段之前, 就已經f[j] = true
2.在i階段之前, 就已經f[j - i] = true
於是,可以貪心, 設used[j] 表示f[j]在階段i是為true的情況下至少需要多少塊i種硬幣
這樣上面的** for(j) for(k) 迴圈可以優化為1維,直接正序掃面
當(!f[j] && f[j - i] && used[j - i] < a[i])才可以轉移
巧妙利用其只求可行性,既不二分也不單調佇列
#include using namespace std;
const int maxn = 1e5 + 5;
int a[101], c[101], n, m;
int f[maxn], cnt, used[maxn];
int main()
cout << cnt << '\n';
} return 0;
}
多重揹包問題 硬幣
給定n種硬幣,其中第 i 種硬幣的面值為ai,共有ci個。從中選出若干個硬幣,把面值相加,若結果為s,則稱 面值s能被拼成 求1 m之間能被拼成的面值有多少個。輸入格式 輸入包含多組測試用例。每組測試用例第一行包含兩個整數n和m。第二行包含2n個整數,分別表示a1,a2,an和c1,c2,cn。當輸...
最少硬幣問題(多重揹包)
time limit 1000 ms memory limit 65536 kib submit statistic problem description 設有n種不同面值的硬幣,各硬幣的面值存於陣列t 1 n 中。現要用這些面值的硬幣來找錢。可以使用的各種面值的硬幣個數存於陣列coins 1 n...
python多重揹包 多重揹包
多重揹包問題 有 n 種物品和乙個容量是 v 的揹包。第 i 種物品最多有 si 件,每件體積是 vi,價值是 wi。求解將哪些物品裝入揹包,可使物品體積總和不超過揹包容量,且價值總和最大。輸出最大價值。資料範圍 0 n v 100 0 vi wi si 100 樸素版多重揹包問題 樸素版完全揹包問...