【codevs2144】砝码称重2,哈希什么的都去死吧

砝码称重 2
时间限制: 1 s
空间限制: 16000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
有n个砝码,现在要称一个质量为m的物体,请问最少需要挑出几个砝码来称?

注意一个砝码最多只能挑一次

输入描述 Input Description
第一行两个整数n和m,接下来n行每行一个整数表示每个砝码的重量。

输出描述 Output Description
输出选择的砝码的总数k,你的程序必须使得k尽量的小。

样例输入 Sample Input
3 10
5
9
1

样例输出 Sample Output
2

数据范围及提示 Data Size & Hint
1<=n<=30,1<=m<=2^31,1<=每个砝码的质量<=2^30
写在前面:我就是不会写C++自带的队列,哈希和堆……
————————————————————————————————————————————————————————
写在前面:如果我们用暴力的话回过60%的点,但是之后就死活AC不了,无奈看了看题解,但发现每一个能看懂代码的(想法能理解,但是一用hash就看不懂了),最后怒打排序+二分过的,排序后分成两部分,逐个dfs求和,每个部分最多2^15-1个,所以数组还是存的下的,然后逐个求差并在另一个数组内查找就可以了
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[31],n,m,l1,l2;
struct os
{
    int num,w;//num代表所用砝码数,w指称出的质量
}hash1[400000],hash2[400000];
int comp(os x,os y)
{
    return x.w<y.w;
}
void dfs1(int x,int y,int z)
{
    if (x>n/2) return;
        hash1[++l1].num=y+1;
        hash1[l1].w=z+a[x];
        dfs1(x+1,y+1,z+a[x]);
        dfs1(x+1,y,z);
}
void dfs2(int x,int y,int z)
{
    if (x>n) return;
        hash2[++l2].num=y+1;
        hash2[l2].w=z+a[x];
        dfs2(x+1,y+1,z+a[x]);
        dfs2(x+1,y,z);
}
int find(int x)
{
    int l=0,r=l2,mid=(l2+1)/2;
    while (l<=r)
    {
        if (hash2[mid].w>x) {r=mid-1;mid=(l+r)/2;}
        if (hash2[mid].w<x) {l=mid+1;mid=(l+r)/2;}
        if (hash2[mid].w==x) return mid;
    }
    return -1;
}
main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    l1++;
    l2++;
    dfs1(1,0,0);
    sort(hash1+1,hash1+l1+1,comp);
    dfs2(n/2+1,0,0);
    sort(hash2+1,hash2+l2+1,comp);
    int minn=100;
    for (int i=1;i<=l1;i++)
    {
        int flag=find(m-hash1[i].w);
        if (flag!=-1) 
        minn=min(minn,hash1[i].num+hash2[flag].num);
    }
    printf("%d",minn);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值