蓝桥杯——卖瓜

问题描述
小蓝正在一个瓜摊上买瓜。瓜摊上共有n个瓜,每个瓜的重量为Ai
小蓝刀功了得,他可以把任何瓜劈成完全等重的两份,不过每个瓜只能劈一刀。
小蓝希望买到的瓜的重量的和恰好为m.
请问小蓝至少要劈多少个瓜才能买到重量恰好为m的瓜。如果无论怎样小蓝都无法得到总重恰好为m的瓜,请输出-1.
输入格式
输入的第一行包含两个整数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.

解题思路

本题我第一个想到的是dfs,维护一个最小的劈瓜次数ans,用一个瓜数组记录每个瓜的重量,遍历每一个瓜,可以分成三种情况,选一个完整的瓜,不选该瓜,切一刀选半个瓜,后续分别对应瓜状态数组f[i]=1,2,3,0 (0为该瓜还未考虑到),dfs函数传递3个参数,分别是瓜的编号i,已经挑选的瓜总量sum,切的次数cnt。判断边界即为挑选的瓜数sum达到需要的数量m,或者遍历完所有瓜。大概思路是这样,但本题需要剪枝,如果不剪枝只能得一部分分数。剪枝有两次,一是当后续方案中劈瓜次数cnt>=ans时可直接舍弃该方案,直接返回。二是当中途挑选的瓜重量sum+b[i]<m时(此处b[i]为后缀和,即当前重量加上后面所有瓜重量都小于所需重量),舍弃该方案,直接返回。值得注意的是做完剪枝后还是不能得满分,后续看了大佬的题解,此题还需要排序,将重量大的瓜放在前面优先考虑,可以减少遍历时间。

完整代码

#include <iostream>
#include <algorithm>
using namespace std;
int ans=35,n,m,q[50],f[50];//f[i]为0为暂未考虑,为1为选,为2为不选,为3为切一刀选一半
long long a[50],b[50],total=0;
void dfs(int i,double sum,int cnt){//瓜编号,已得瓜重量,切的瓜数
     if(cnt>=ans) return;//剪枝
     if(sum==m){
       if(cnt<=ans) ans=cnt;//满足条件,维护最小ans
       }
     if(sum>=m || i>n || sum+b[i]<m) return;//剪枝

     //1
     f[i]=1;
     dfs(i+1,sum+q[i],cnt);
     f[i]=0;

     //2
     f[i]=2;
     dfs(i+1,sum,cnt);
     f[i]=0;

     //3
     f[i]=3;
     dfs(i+1,sum+q[i]/2.0,cnt+1);
     f[i]=0;

}
int main()
{
  cin>>n>>m;
  for(int i=1;i<=n;i++){
    cin>>q[i];
    total+=q[i];
  }

  sort(q+1,q+n+1,greater<int>());//反向排序,从大到小 
  for(int i=n;i>=1;i--){
   
    b[i]=q[i]+b[i+1];//后缀和,即从i到n的和
  }

  if(total<m){
    cout<<-1;
  }//瓜总量小于m直接输出-1
  else{
   dfs(1,0,0);
   if(ans==35) cout<<-1;//ans初始值没有改变,说明没有任何一种方案满足条件
   else cout<<ans;
  }
  return 0;
}

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Java中,带分数可以用分数类来表示。下面是一个简单的带分数类的实现: ```java public class Fraction { private int integer; private int numerator; private int denominator; public Fraction(int integer, int numerator, int denominator) { this.integer = integer; this.numerator = numerator; this.denominator = denominator; simplify(); } private void simplify() { if (numerator < 0 && denominator < 0) { numerator = -numerator; denominator = -denominator; } if (denominator < 0) { numerator = -numerator; denominator = -denominator; } if (integer < 0 && numerator > 0) { numerator = -numerator; } if (integer < 0 && numerator == 0) { integer = -integer; } if (numerator >= denominator) { integer += numerator / denominator; numerator = numerator % denominator; } int gcd = gcd(numerator, denominator); numerator /= gcd; denominator /= gcd; } private int gcd(int a, int b) { if (b == 0) { return a; } return gcd(b, a % b); } public Fraction add(Fraction other) { int newNumerator = this.numerator * other.denominator + other.numerator * this.denominator; int newDenominator = this.denominator * other.denominator; int newInteger = this.integer + other.integer; return new Fraction(newInteger, newNumerator, newDenominator); } public String toString() { if (integer == 0 && numerator == 0) { return "0"; } String result = ""; if (integer != 0) { result += integer; if (numerator != 0) { result += "_"; } } if (numerator != 0) { result += numerator + "/" + denominator; } return result; } } ``` 这个带分数类实现了以下功能: - 构造函数可以根据整数部分、分子和分母创建一个带分数对象。 - simplify() 方法可以将带分数对象化简,如将负号移到分子上、将整数部分和真分数部分合并、将分数化简等。 - add() 方法可以将两个带分数对象相加,返回一个新的带分数对象。 - toString() 方法可以将带分数对象转换为字符串形式。 这个类实现了带分数的加法操作,可以参考这个类来实现其他的运算操作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值