砝码称重2

【题目描述】

有n个砝码,现要称一个质量为m的物体,询问最少需要挑出几个砝码来称,一个砝码最多只能挑一次。

【输入描述】

第一行输入两个整数n和m;

接下来n行,每行输入一个整数表示砝码的重量。

【输出描述】

输出一个整数表示最少需要的砝码数。

【样例输入】

3 10

5

9

1

【样例输出】

2

【数据范围及提示】

1 <= n <= 30,1 <= m <= 231,1 <= 每个砝码的质量 <= 230

源代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int m,n,L1=1,L2=1,Min=1000000000,i[31];
struct Node
{
    int Sum,Weight;
}F1[400000],F2[400000]; //计算好情况数目,别想当然。
int Rule(Node t1,Node t2)
{
    return t1.Weight<t2.Weight;
}
void DFS1(int t,int S,int W) //t代表当前砝码编号,S代表已使用的砝码数量,W代表已使用的砝码总重。
{
    if (t>(n>>1))
      return;
    F1[++L1].Sum=S+1;
    F1[L1].Weight=W+i[t];
    DFS1(t+1,S+1,W+i[t]); //取还是不取。
    DFS1(t+1,S,W);
}
void DFS2(int t,int S,int W) //同理于上。
{
    if (t>n)
      return;
    F2[++L2].Sum=S+1;
    F2[L2].Weight=W+i[t];
    DFS2(t+1,S+1,W+i[t]);
    DFS2(t+1,S,W);
}
int Find(int t) //排序之后,二分查找。
{
    int Left=0,Right=L2,Mid=L2>>1;
    while (Left<=Right)
    {
        if (F2[Mid].Weight>t)
        {
            Right=Mid-1;
            Mid=(Left+Right)>>1;
        }
        if (F2[Mid].Weight<t)
        {
            Left=Mid+1;
            Mid=(Left+Right)>>1;
        }
        if (F2[Mid].Weight==t)
          return Mid;
    }
    return -1;
}
int main() //然而并没有用到Hash。
{
    scanf("%d%d",&n,&m);
    for (int a=1;a<=n;a++)
      scanf("%d",&i[a]);
    sort(i+1,i+n+1);
    DFS1(1,0,0);
    sort(F1+1,F1+L1+1,Rule);
    DFS2((n>>1)+1,0,0);
    sort(F2+1,F2+L2+1,Rule);
    for (int a=1;a<=L1;a++)
    {
        int t=Find(m-F1[a].Weight);
        if (t!=-1) //符合条件。
          Min=min(Min,F1[a].Sum+F2[t].Sum);
    }
    printf("%d",Min);
    return 0;
}

/*
    解题思路:
        本质上就是定义一个左根堆和一个右根堆,这样可以节省很多空间。之所以排序,是为了保证二分的正确性,然后进行查找匹配。
*/

转载于:https://www.cnblogs.com/Ackermann/p/5903333.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值