首页 > 编程语言 >2023第14届蓝桥杯大赛软件赛省赛C/C++大学A组第6题题解

2023第14届蓝桥杯大赛软件赛省赛C/C++大学A组第6题题解

时间:2024-03-27 18:33:31浏览次数:25  
标签:重量 组第 cut int 题解 sum dfs 蓝桥 id

目录

问题描述:

方法一:dfs暴力模拟(45%)

方法二:dfs剪枝(100%)


问题描述:

        小蓝正在一个瓜摊上买瓜。瓜摊上共有 n 个瓜,每个瓜的重量为 Ai 。 小蓝刀功了得,他可以把任何瓜劈成完全等重的两份,不过每个瓜只能劈 一刀。 小蓝希望买到的瓜的重量的和恰好为m。 请问小蓝至少要劈多少个瓜才能买到重量恰好为 m 的瓜。如果无论怎样小 蓝都无法得到总重恰好为 m 的瓜,请输出 −1 。

输入格式:

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

输出格式:

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

评测用例规模与约定:         对于20%的评测用例,1≤n ≤10 ;         对于60%的评测用例,1≤n ≤20 ;         对于100%的评测用例,1≤n≤30,1≤Ai≤10^9,1 ≤m≤ 10^9。

方法一:dfs暴力模拟(45%)

        将所有瓜按顺序排成一排,从前往后选择每个瓜。对于每一个瓜,有三种选择:不要,切一半,拿整个。分别切了0,1,0刀。不能切一刀之后两半全拿,这样不符合题意的最少劈的次数。         可以使用dfs模拟这个从前往后选择的过程,dfs(id,sum,cut)中的三个参数分别表示当前选择的是第几个瓜,之前一共拿了多少重量的瓜,之前一共劈了多少刀。上面说的三种选择对应的函数就是:         1、不拿dfs(id+1,sum,cut)         2、切一刀,拿一半dfs(id+1,sum+a[id]/2,cut)         3、不切,拿整个dfs(id+1,sum+a[id],cut)         当sum==想要的重量的m时,就可以比较当前劈的次数与之前最少的次数哪个更小了。
#include <iostream>
using namespace std;
double a[35];
int n,m;
int ans=35;
void f(int id,double sum,int cut)//当前选择第几个瓜,已拿重量,已劈次数
{
  if(sum==m)//拿够了
  {
    ans=min(ans,cut);
    return ;
  }
  if(id>n) return ;//所有瓜都选择完了
  f(id+1,sum,cut);//不拿这个瓜
  f(id+1,sum+a[id]/2,cut+1);//切一刀,拿一半
  f(id+1,sum+a[id],cut);//不切,拿整个
}
int main()
{
  cin>>n>>m;
  for(int i=1;i<=n;i++)
    cin>>a[i];
  f(1,0,0);
  if(ans<35) cout<<ans;
  else cout<<"-1";
  return 0;
}

方法二:dfs剪枝(100%)

        分析上一个代码,当n=30时执行了3^30次dfs函数,其中有很多情况是不需要执行的。剪枝有以下几种思路:

        1、当前获得的总重量已经超过目标m,不需要继续执行。

        2、当前劈的次数超过了目前最少的次数,不需要继续执行。

        3、如果之后所有的瓜全部都要,加上当前的重量,也不能达到目标m,不需要继续执行。为了快速计算之后所有瓜的重量,可以使用前缀和预处理瓜的重量。为了更早进行剪枝,可以将瓜的重量从大到小排序。

#include <iostream>
#include<algorithm>
using namespace std;
double a[35];
double b[35];
int n,m;
int ans=35;
void f(int id,double sum,int cut)//当前选择第几个瓜,已拿重量,已劈次数
{
  if(sum==m)//拿够了
  {
    ans=min(ans,cut);
    return ;
  }
  if(id>n) return ;
  if(sum>m||cut>ans) return ;
  if(sum+b[n]-b[id-1]<m) return ;//剩下的瓜全拿,也不够目标重量
  f(id+1,sum,cut);//不拿这个瓜
  f(id+1,sum+a[id]/2,cut+1);//切一刀,拿一半
  f(id+1,sum+a[id],cut);//不切,全拿
}
int main()
{
  cin>>n>>m;
  for(int i=1;i<=n;i++)
    cin>>a[i];
  sort(a+1,a+n+1,greater<double>());//从大到小排序
  for(int i=1;i<=n;i++)
    b[i]=a[i]+b[i-1];//前缀和预处理
  f(1,0,0);
  if(ans<35) cout<<ans;
  else cout<<"-1";
  return 0;
}

        注意需要将瓜的重量除以2,直接用int型/2是整除应该使用double型,或者将所有瓜的重量和m都乘以2,由于数据范围时10^9,最好使用long long型。

        我在写这个题的时候将数组下标从1开始存,排序的时候sort第二个参数应该加n+1,因为这里写错了导致卡了很久,去读了官方这题的题解感觉很奇怪,将瓜分成两部分分别dfs,后一部分dfs时再二分搜索前一部分存的对应重量的刀数相加。

标签:重量,组第,cut,int,题解,sum,dfs,蓝桥,id
From: https://blog.csdn.net/qq_40485202/article/details/137084596

相关文章

  • 蓝桥杯单片机AT24C02
    一个简单的示例程序,统计开机次数。代码如下:#include<STC15F2K60S2.H>#include<intrins.h>#include"onewire.h"#include"iic.h"u8flag_display=0;u8flag_ds18b20=0;u8flag_at=0;u8at=0;u8temp=0;u8a[8]={10,10,10,10,10,10,10,10};voidctr......
  • P7137 [THUPC2021 初赛] 切切糕 题解
    题目传送门前置知识博弈论解法由于本题是CF1628D1GameonSum(EasyVersion)的扩展,故先从CF1628D1GameonSum(EasyVersion)讲解。CF1628D1GameonSum(EasyVersion)设\(x_{i}\)表示第\(i\)轮时Alice选择的数。设\(f_{i,j}\)表示已经进行了\(i\)轮,且......
  • 动态规划刷题(算法竞赛、蓝桥杯)--数字三角形(线性DP)
    1、题目链接:[USACO1.5][IOI1994]数字三角形NumberTriangles-洛谷#include<bits/stdc++.h>usingnamespacestd;intr;constintN=1010;inta[N][N];intmain(){ cin>>r; for(inti=1;i<=r;i++){ for(intj=1;j<=i;j++){ cin>>a[i][j]; ......
  • Spring Boot 工程开发常见问题解决方案,日常开发全覆盖
    本文是SpringBoot开发的干货集中营,涵盖了日常开发中遇到的诸多问题,通篇着重讲解如何快速解决问题,部分重点问题会讲解原理,以及为什么要这样做。便于大家快速处理实践中经常遇到的小问题,既方便自己也方便他人,老鸟和新手皆适合,值得收藏......
  • 【赛题解析】【网络建设与运维】第三阶段Linux Vsftpd部分答案解析
    培训、环境、资料、考证公众号:波比网络公众号2:波比网络工作室网络建设与运维群:685678820波比网络专注于技能提升,赋能ftp服务任务描述:请采用ftp服务器,实现文件安全传输。1.配置 linux1为ftp服务器,安装vsftpd,新建本地用户xiaoming,本地用户登陆ftp后的目录为/var/ft......
  • CF1879的题解
    (一)对于第一个问题,直接搜出字符串中有多少个仅由\(0\)或\(1\)组成的串组成的。对于第二个问题,每个串只有一个能选,然后选择顺序有所不同,具体看代码。(二)AC代码。#defineintlonglong#definemd998244353usingnamespacestd;intt,s[200010];charch[200010];sign......
  • CF340B的题解
    (一)枚举对角线。然后分别找正在对角线上方的点与对角线端点构成三角形面积的最大值。和在对角线下方的点与对角线端点构成三角形面积的最大值。如果所有点都在同侧,那么不算。通过过两点直线的解析式求出另一点在直线的哪一侧。(二)AC代码。#include<bits/stdc++.h>#define......
  • CF1864C的题解
    (一)可以将\(x\)转为二进制。考虑一个数的二进制\((1\dots10\dots0)\)。其中,第一个省略号中有什么不确定,第二个省略号里都是\(0\)。易得,每个数都可以看成这种形式。那么可以每次去掉最后一位的\(1\),易证减去的数是原数的因数。最后会得到形如\((10\dots0)\),省略号中全是......
  • AT_abc345_c的题解
    (一)首先交换相同字符不改变字符串形态,那么就先统计是否有相同字符。交换不同字符容易证明不同操作后字符串各不相同。用前缀和或后缀和维护\(i+1\)到\(n\)中与\(i\)位置字符不同的数量。(二)AC代码。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd......
  • AT_abc344_e的题解
    (一)这次ABC有点水。每个数记录前面那个数,和后面那个数。对于每个数,开个数组记录值,用map记录一个值的位置(二)AC代码。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intpre[400010],cnt,las[400010],a[400010],n,q;map<int,int>mp;signedmain(......