单词长度最长为13,故可以用二进制压缩成2^13的方案,二进制中1代表学习了,0代表未学习。
然后可以枚举每种方案以及每种方案可以由什么方案转移而来,并且存入vector数组中。
即 01 <--- 00,10 <--- 00, 11 <--- 10,11 <--- 01, 11 <--- 00(前提学习的时间没有超过w)
转移方程为 dp[ i ] = min(dp[ i ],dp[ j ] + 1)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
vector<int> v[N];
int dp[N], dp[20];
int main() {
int n, w;
cin >> n >> w;
int len = 0;
for (int i = 1; i <= n; i++) {
int x; cin >> x;
len = max(len, x);
a[x - 1]++;
}
int ans = 0;
for (int i = 0; i <= len; i++) {
if (a[i]) ans += (1 << i);//预处理出最终状态
}
for (int i = 0; i < (1 << len); i++) {
for (int j = 0; j < (1 << len); j++) {
int temp = 0;
int k = 0;
for (k; k < len; k++) {
int x1 = (i >> k) & 1;
int x2 = (j >> k) & 1;
if (x1 == 1 && x2 == 0) temp += a[k];
if (x1 == 0 && x2 == 1) break;
}
if (k == len && temp <= w) v[i].push_back(j);
}
}
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for (int i = 0; i <= ans; i++) {
for (auto it: v[i]) {
dp[i] = min(dp[i], dp[it] + 1);
}
}
cout << dp[ans] << "\n";
return 0;
}