1. 程式人生 > >2017騰訊校招筆試程式設計題-拼湊零錢

2017騰訊校招筆試程式設計題-拼湊零錢

今天剛剛參加了2017年的騰訊校招線上筆試,其中有一道程式設計題是這樣的:小明很富有,有幣值為2^n(n=0,1,2,3)的硬幣各兩個,即有兩個1塊錢的硬幣,有兩個2塊錢的硬幣,有兩個四塊錢的硬幣。。。,現在輸入一個正整數數m(0<m<10^18),請問從小明的硬幣中湊出這個數值,請問一共有多少中組合方式。

比如輸入6,則輸出3,因為6=2+4=1+1+4=1+1+2+2。(這裡可以看出,每一種組合方法的個數是不用的,四個數的組合方法有一種,3個數的組合方法有一種,2個數的組合方法有一種)

下面是我的解法:
思路:如果每種幣值的硬幣只有一個,那麼這個數的二進位制形式中1的個數就是唯一一種拼湊方法。比如說6=110,也就是4+2;如果每個幣值的硬幣有兩個,那麼可以用兩個數來查詢拼湊方法,比如6=4+2=3+3=5+1;但是要避免重複運算,比如7=1+6=3+4,但是都是由1+2+4一種相同的方式組合而來的,那麼如何避免重複呢,經過發現,每一個組合(拼湊方法)的數的個數是不同的,因此,可以用一個數組來記錄個數為n的組合,如果已經組合過了,就不重複計算。比如7=1+6=3+4,但是6=110一共有兩個1,1有一個1,1+6一共有三個1,因此是一種拼湊方法,但是3有兩個1,4有一個1,3+4有2+1=3個1,因此不重複計算。

#include <iostream>
using namespace std;
#include<set>
int main()
{
    long n,k,cnt=0,t,p;
    set<long> s;///這個集合用來去重
    cin>>n;
    long i,j;
    for(i=0;i<=n/2;++i){
        j=n-i;
        p=~(i^j);
        if(s.find(p)==s.end()){///如果這個湊法跟之前的不重複
             s.insert(p);
             ++cnt;
        }
    }
    cout<<cnt<<endl;
    return 0;
}