第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 F题

问题描述

在这里插入图片描述


格式输入

输入的第一行包含两个整数 n, m,用一个空格分隔,分别表示瓜的个数和小蓝想买到的瓜的总重量。
第二行包含 n 个整数 Ai,相邻整数之间使用一个空格分隔,分别表示每个瓜的重量。


格式输出

输出一行包含一个整数表示答案。


样例输入

3 10
1 3 13


样例输出

2


评测用例规模与约定

对于 20% 的评测用例,∑n ≤ 10 ;
对于 60% 的评测用例,∑n ≤ 20 ;
对于所有评测用例,1 ≤ n ≤ 30,1 ≤ Ai ≤ 10^9 ,1 ≤ m ≤ 10^9 。


解析

看到这题大家会不会想起一个人,强哥。在这里插入图片描述

买瓜应该还有点小问题


参考程序

25%

#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m;
    cin >> n >> m;
    m *= 2;
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    int N = n / 2;
    unordered_map<int, int> mp(1024);
    mp.max_load_factor(0.25);
    mp[0] = 0;
    function<void(int, int, int, i64)> dfs = [&](int j, int B, int res, i64 sum) {
        if (sum >= m || j == N) {
            if (sum <= m) {
                mp[sum] = res;
            }
            return;
        }
        if (B == 0) {
            sum += a[j];
            res++;
        } else if (B == 1) {
            sum += a[j] * 2;
        }
        for (int i = 0; i < 3; i++) {
            dfs(j + 1, i, res, sum);
        }
    };
    for (int i = 0; i < 3; i++) {
        dfs(0, i, 0, 0);
    }
    int ans = 1E9;
    function<void(int, int, int, i64)> dfs_again = [&](int j, int B, int res, i64 sum) {
        if (sum >= m || j == n) {
            if (sum <= m && mp.count(m - sum)) {
                ans = min(ans, mp[m - sum] + res);
            }
            return;
        }
        if (B == 0) {
            sum += a[j];
            res++;
        } else if (B == 1) {
            sum += a[j] * 2;
        }
        for (int i = 0; i < 3; i++) {
            dfs_again(j + 1, i, res, sum);
        }
    };
    for (int i = 0; i < 3; i++) {
        dfs_again(N, i, 0, 0);
    }
    cout << ans << '\n';

    return 0;
}

85%

#include <stdio.h>
#include <algorithm>
#include <bitset>

const int HALF = 14348907;

int n, m, h, H, ans, a[30];

std::bitset<400000009> bloom;

std::pair<int, int> half[HALF];

void make(int i, int w, int k) {
    if (i < 0) half[H++] = {w, k}, bloom[w % 400000009] = 1;
    else {
        make(i - 1, w, k);
        if (w <= m - a[i])
            make(i - 1, w + a[i], k + 1);
        if (w <= m - (a[i] << 1))
            make(i - 1, w + (a[i] << 1), k);
    }
}

void dfs(int i, int w, int k) {
    if (i == n) {
        if (bloom[w % 400000009]) {
            int l = 0, r = h;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (half[mid].first < w) l = mid + 1;
                else r = mid;
            }
            if (half[l].first == w)
                ans = std::min(ans, half[l].second + k);
        }
    } else {
        dfs(i + 1, w, k);
        if (w >= a[i])
            dfs(i + 1, w - a[i], k + 1);
        if (w >= (a[i] << 1))
            dfs(i + 1, w - (a[i] << 1), k);
    }
}

int main() {
    scanf("%d %d", &n, &m), m <<= 1, ans = n << 1;
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    std::random_shuffle(a, a + n);
    make(n / 2, 0, 0);
    std::sort(half, half + H);
    for (int i = 1; i < H; ++i)
        if (half[i].first != half[h].first) half[++h] = half[i];
    dfs(n / 2 + 1, m, 0);
    printf("%d", ans > n ? -1 : ans);
}



100%

#include <iostream>
#include <algorithm>
using namespace std;
int n,ans=50;
long long m,a[50],sum[50];
void dfs(long long S,int i,int cnt){
  if(cnt>=ans) return;
  if(S==m) ans=cnt;
  if(i>n||S>m||S+sum[i]<m) return;
  dfs(S,i+1,cnt);
  dfs(S+a[i],i+1,cnt);
  dfs(S+a[i]/2,i+1,cnt+1);
}
int main()
{
  // 请在此输入您的代码
  cin>>n>>m;
  m<<=1;
  for(int i=0;i<n;++i){
    cin>>a[i];
    a[i]<<=1;
  }
  sort(a,a+n,greater<>());
  for(int i=n-1;i>=0;--i){
    sum[i]=sum[i+1]+a[i];
  }
  dfs(0,0,0);
  if(ans==50){
    cout<<-1<<endl;
  }else{
    cout<<ans<<endl;
  }
  return 0;
}

以个人刷题整理为目的,如若侵权,请联系删除~

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值