题目链接:https://www.luogu.com.cn/problem/P9234
题目思路:
每个瓜有三种选择,不要/劈开/要整个,显然整个决策做下来是树状的,于是我们考虑用dfs,每次能拿到相对重量的瓜时就统计劈开数量。如果直接写不优化,恭喜你喜提20分,于是我们考虑剪枝。
最容易想到,当先择了的西瓜总量大于需要时可以剪掉。先给a排个序然后从大到小搜似乎也是个优化选项,恭喜您离100分又接近了一些。我们每次把当前劈开瓜的次数也记录下来,当当前次数大于等于之前搜出过的最小值,也剪掉。现在提交喜提52分,那么如何继续优化呢?当前选择的西瓜总量+剩下的西瓜总量小于所需时,剪掉,我们使用前缀和记录剩下的西瓜总量。注意存在买不到西瓜的可能。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll maxn = 1e18;
const int MOD = 998244353;
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
int n, m;
ll a[35];
int ans = INT_MAX;
ll pre[35];
void dfs(int pos, ll sum, int t) {//当前层数,剩下的瓜总量,当前劈开次数
if (sum == m) {
ans = min(ans, t);
return;
}
if (m > sum + pre[pos] || sum > m || t >= ans) { return; }
if (pos < 1) return;
dfs(pos - 1, sum + a[pos], t);
dfs(pos - 1, sum + a[pos] / 2, t + 1);
dfs(pos - 1, sum, t);
}
void solve() {
cin >> n >> m;
m *= 2;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] *= 2;
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++) {
pre[i] += pre[i - 1] + a[i];
}
dfs(n, 0, 0);
if (ans == INT_MAX)
cout << -1 << '\n';
else
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
std::cout.tie(0);
int t1 = 1;
//cin >> t1;
while (t1--)
solve();
return 0;
}