传送门:传送门
思路:
用二进制来表示已经获得的糖果种类, 例如,现在有口味为1和3的糖,那么对应的二进制状态就是101,可以通过按位与运算合并
101 = 001 | 100
用dp[i]表示为了达到状态i所需购买的最小包数。状态转移的话,如从状态j借助a[i]转移到 j | a[i],对应为dp[j | a[i]] = min(dp[j | a[i]], dp[j] + 1)。最终的答案就是dp[(1 << m)-1]。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = (1 << 20) + 10;
int n, m, k;
int a[N], dp[M];
int main() {
int x;
scanf("%d%d%d", &n, &m, &k);
memset(dp, -1, sizeof dp);
for (int i=1;i<=n;i++) {
for (int j=1;j<=k;j++) {
scanf("%d", &x);
a[i] |= (1 << (x-1)); // 例: x=3时, 表示为100, 即2^(3-1)对应的二进制
}
dp[a[i]] = 1; // 一袋就行
}
for (int i=1;i<=n;i++) {
for (int j=0;j<(1 << m);j++) {
if (dp[j] == -1) continue;
else if (dp[j | a[i]] == -1) dp[j | a[i]] = dp[j] + 1;
else dp[j | a[i]] = min(dp[j | a[i]], dp[j] + 1);
}
}
printf("%d\n", dp[(1 << m) - 1]);
return 0;
}