[蓝桥杯]买瓜

蓝桥账户中心

题意

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   能避免很多不必要的递归

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值