1. 程式人生 > >wikioi-天梯-提高一等-雜湊表-2144:砝碼稱重2

wikioi-天梯-提高一等-雜湊表-2144:砝碼稱重2

題目描述 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

型別:其他  難度:2

題意:給出n個數,要求從中挑出k個數,使它們的和為m,求最小的k

分析:一個簡單的思路:

1、就是把n個數分成兩份,分別求每份的數所有可能取的和,用cnt1和cnt2兩個雜湊表記錄,其中cnt1[i]=j表示最少需要湊出和為i,至少需要j個數。

遍歷方法可以用二進位制表示每個數是否取,比如有5個數,那麼遍歷1 - (2^5-1),每個數二進位制為1,則將這個數累加,將累加的和作為雜湊表的key,選取的個數作為雜湊表的value,若比之前的小或是新出現的則更新雜湊表對應項

2、對於兩個雜湊表cnt1和cnt2,遍歷其中一個雜湊表,設當前遍歷的項為cnt1[i]=j,那麼找cnt2[m-i]=k是否存在,若存在,那麼j+k即為總共需要取的個數,記錄最小值即為所求

3、最後分別看cnt1[m]和cnt2[m]是否存在,就是單獨取兩部分的和就能構成結果,更新結果為最小值

用stl map實現雜湊的功能,比自己寫雜湊稍微慢了點,不過夠用了。

本來嘗試用stl hash_map實現,但是hash_map不是ansi c的標準,我用的編譯器要加using namespace __gnu_cxx,並且wikioi的編譯器不認,就沒有用。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;

map<long long,int> cnt1,cnt2;

int main()
{
    int n;
    long long m;
    vector<int> da;
    scanf("%d%lld",&n,&m);
    
    for(int i=0; i<n; i++)
    {
        int tmp;
        scanf("%d",&tmp);
        da.push_back(tmp);
    }
    sort(da.begin(),da.end());
    
    int l1 = da.size()/2;
    int l2 = da.size() - l1;
    
    for(int i=1; i<1<<l1; i++)
    {
        long long sum=0;
        int tc = 0;
        for(int j=i,k=0; j; j>>=1,k++)
            if(j&1)
            {
                sum += (long long)da[k];
                tc++;
            }
        
        int now = cnt1[sum];
        if(!now || tc<now) cnt1[sum] = tc;
    }
    for(int i=1; i<1<<l2; i++)
    {
        long long sum=0;
        int tc = 0;
        for(int j=i,k=l1; j; j>>=1,k++)
            if(j&1)
            {
                sum += (long long)da[k];
                tc++;
            }
        
        int now = cnt2[sum];
        if(!now || tc<now) cnt2[sum] = tc;
    }
    
    int ans = 50;
    
    map<long long,int>::iterator it;
    for(it=cnt1.begin(); it!= cnt1.end(); it++)
    {
        long long left = m-it->first;
        int tmp = it->second;
        
        if(left > 0)
        {
            int tmp2 = cnt2[left];
            if(tmp2)
            {
                tmp += tmp2;
                ans = min(ans,tmp);
            }
        }
    }
    int r1 = cnt1[m];
    int r2 = cnt2[m];
    if(r1) ans = min(ans,r1);
    if(r2) ans = min(ans,r2);
    printf("%d\n",ans);
}


相關推薦

wikioi-天梯-提高一等--2144砝碼2

題目描述 Description 有n個砝碼,現在要稱一個質量為m的物體,請問最少需要挑出幾個砝碼來稱? 注意一個砝碼最多隻能挑一次 輸入描述 Input Description 第一行兩個整數n和m,接下來n行每行一個整數表示每個砝碼的重量。

wikioi-天梯-提高一等-高精度普及-3118高精度練習之除法

題目描述 Description 給出兩個正整數A和B,計算A/B整數部分的值。保證A和B的位數不超過500位。 輸入描述 Input Description 讀入兩個用空格隔開的正整數 輸出描述 Output Description 輸出

Hash概念與基本操作

什麼是Hash Hash就像是一個桶排,那隻不過是把各個元素的數值當做下標進行儲存.其最常用的用途就是用來判重.但是,如何對字串進行判重,不可能一個一個往前超,若n上萬則顯然不可行.我們可以選擇進行Hash,將每一個字串或者大數字進行一定的操作即可進行. 對大整數型別進行Hash 取模法 對於每一個

wikioi 2144 砝碼 2 STL_map

看似dp,但是資料太大,不過n很小,可以暴力解決。 由於30個數組合情況太多,所以可以分成兩邊,首先預處理前n/2個數能組成哪些數,並且最小消耗多少砝碼,map儲存下來。 然後處理右邊能組合成什麼數,相加就夠了。 注意這樣會漏掉兩種情況,就是光一邊就能組成最終答案的(因為m

2144 砝碼 2 用map離散化hasi+二分搜尋

2144 砝碼稱重 2  時間限制: 1 s  空間限制: 16000 KB  題目等級 : 鑽石 Diamond 題解 題目描述 Descrip

CODE【VS】2144 砝碼2(dfs+剪枝)

題目描述 Description 有n個砝碼,現在要稱一個質量為m的物體,請問最少需要挑出幾個砝碼來稱? 注意一個砝碼最多隻能挑一次 輸入描述 Input Description 第

CODEVS 2144 砝碼2

//二分dfs,最後合併 #include<bits/stdc++.h> using namespace std; const int maxn = 400000; int n, m,

Hash(/)中衝突處理及命中計算

前言   本片部落格主要講的是雜湊表中簡單的衝突處理的方法,以及命中率計算。原理方面基本沒有講解,基本就講個方法,主要用於知識記錄以及幫助一些刷題玩家瀏覽。   簡而言之,不講技術,只講方法。 引言   寫這篇部落格的契機是在刷pat甲級題遇到了一道寫雜湊的題目,結果英文太次被欺負了。之後靠翻譯讀懂題

查詢演算法 淺談演算法和資料結構: 七 二叉查詢樹 淺談演算法和資料結構: 十一

閱讀目錄 1. 順序查詢 2. 二分查詢 3. 插值查詢 4. 斐波那契查詢 5. 樹表查詢 6. 分塊查詢 7. 雜湊查詢   查詢是在大量的資訊中尋找一個特定的資訊元素,在計算機應用中,查詢是常用的基本運算,例如編譯程式中符號表的查詢。本文

【LeetCode】 hashmap(共88題)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica } 【1】Two Sum  【3】Longest Substring Without Repeating Characters  【18】4Sum 

記錄一下底層原理

理解HashMap底層,首先應該理解Hash函式 從解決一個問題入手:大量的資料要儲存查詢,構造雜湊表來解決 初步想法 借鑑陣列下標訪問的思路來做,只需知道起始位置和下標值, 不管陣列中有多少個元素,都可以一次訪問到, 將元素和元素位置建立一種一一對應的關係 Hash函式的出現 輸入的元素的範圍

散列表()+衝突的解決方法

轉載http://www.nowamagic.net/academy/detail/3008060 1散列表 1簡單來說就是給一個key,就可以找到對應的key的儲存位置,就像身份證對應一個人一樣 儲存位置 = f(key) 2hashMap的key就是用到散列表 1.1雜湊衝突

九章演算法筆記 8.與堆 Hash & Heap

大綱 cs3k.com 資料結構概述 雜湊表 Hash: a.原理  b.應用 堆 Heap: a.原理    b.應用-優先佇列 Priority Queue  c.替代品-TreeMap   資料結構的兩類問題 cs3k

27-集合--Set及其子類(HashSet+LinkedHashSet+TreeSet)+二叉樹+Comparable+Comparator++HashSet儲存自定義物件+判斷元素唯一的方式

一、Set 1、Set:元素不可以重複,是無序的(存入和取出的順序不一致) 2、Set介面中的方法和Collection中的方法一致 3、Set集合的元素取出方式只有一種:迭代器iterator() Set set = new HashSet(); I

基於實現字典和集合

上一節說到了雜湊表。 我們提到了字典和集合是由雜湊表實現的,具體的實現過程是怎麼樣的呢? 其實很簡單,字典裡面有取值,新增值,正好對應的就是雜湊表中的find和add方法。使用__getitem__和__setitem__代替兩者就可以了。然後對於keys,values取值,只需要遍歷迴圈就行了。 這裡

的原理及實現

雜湊表(Hash table,也叫散列表), 是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。 雜湊表hash table(key,value) 的做法

資料結構基礎之查詢(下)

轉自:http://www.cnblogs.com/edisonchou/p/4706253.html   查詢(下):雜湊表 雜湊(雜湊)技術既是一種儲存方法,也是一種查詢方法。然而它與線性表、樹、圖等結構不同的是,前面幾種結構,資料元素之間都存在某種邏輯關係,可以用連線圖示

構建——優化暴力求解方程

/*  Consider equations having the following form: a*(x1)^2+b*(x2)^2+c*(x3)^2+d*(x4)^2=0 a, b, c, d are integers from the interval [-50,50] and

構造——求前m大的數

Problem Description 給你n個整數,請按從大到小的順序輸出其中前m大的數。 Input 每組測試資料有兩行,第一行有兩個數n,m(0<n,m< 1000000),第二行包含n個各不相同, 且都處於區間[-500000,500

—拉鍊法

public class Link { /** * 有序連結串列連結點 */ public int data; public Link nextLink; public Link(int data){ this.data = data; } publi