题意
n个瓜 每个瓜重量a[i] 每个瓜最多劈一次 每次劈成一半一半 (可能劈成小数)
最少劈几次 能够组合出总重量为m
思路
1≤n≤30,1≤Ai≤1e9,1≤m≤1e9
n非常小 显然是dfs
每个瓜劈开了 就一定要选 不然劈开是没有意义的
所以一共n个瓜 每个瓜有三种选择
①不劈不买
②不劈但买
③劈开必须买
同时记录劈了几个瓜 取min
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define ar2 array<int,2>
#define ar3 array<int,3>
#define ar4 array<int,4>
#define endl '\n'
void cmax(int &a,int b){a=max(a,b);}
void cmin(int &a,int b){a=min(a,b);}
const int N=2e5+10,MOD=1e9+7,INF=0x3f3f3f3f,LINF=LLONG_MAX;const double eps=1e-6;
int a[N];
int suf[N];
int ans=INF,n;
int m;
void dfs(int num,int cnt,int sum){
if(sum>m||cnt>ans) return;
if(sum==m){
cmin(ans,cnt);
return;
}
if(sum+suf[num]<m) return;
if(num>n){
if(sum==m){
cmin(ans,cnt);
}
return;
}
dfs(num+1,cnt,sum);
dfs(num+1,cnt,sum+a[num]);
dfs(num+1,cnt+1,sum+a[num]/2);
}
void solve() {
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],a[i]<<=1;
m<<=1;
sort(a+1,a+1+n,greater<int>());
for(int i=n;i>=1;i--){
suf[i]=suf[i+1]+a[i];
}
dfs(1,0,0.0);
if(ans==INF) ans=-1;
cout<<ans<<endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t=1;
// cin>>t;
while (t--) solve();
}
num表示当前考虑到几号西瓜 cnt表示当前劈了几次 sum表示当前买的总重量
处理技巧
把每个a[i]都*2 m也同步*2 这样就避免了 double运算 我一开始用double做的 只能通过85%的样例
一个显然的剪枝:
当前sum>m cnt>ans 就return
但这样剪枝是不能完全ac的
还要下面这个重要的剪枝优化:
①把a降序排序 能尽快return一些不可能的情况
②便于构造后缀和数组 用来判断当前买了的sum 就算把后面所有的都买了 如果还是到不了m 那就直接return 能避免很多不必要的递归