網易筆試編程題-幸運的袋子

題目描述:
一個袋子裏面有n個球,每個球上面都有一個號碼(擁有相同號碼的球是無區別的)。如果一個袋子是幸運的當且僅當所有球的號碼的和大於所有球的號碼的積。
例如:如果袋子裏面的球的號碼是{1, 1, 2, 3},這個袋子就是幸運的,因爲1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
你可以適當從袋子裏移除一些球(可以移除0個,但是別移除完),要使移除後的袋子是幸運的。現在讓你編程計算一下你可以獲得的多少種不同的幸運的袋子。
輸入描述:
第一行輸入一個正整數n(n ≤ 1000)
第二行爲n個數正整數xi(xi ≤ 1000)
輸出描述:
輸出可以產生的幸運的袋子數
輸入例子:
3
1 1 1
輸出例子:
2
分析:
假設袋子中有數字1,1,1,1,2,2,2,2這八個數字,那麼是幸運袋子的組合就可能是:
第一種:1,1,1,1,2,2,2
第二種:1,1,1,1,2,2
第三種:1,1,1,1,2
第四種:1,1,1,1
第五種:1,1,1,2,2,2
第六種:1,1,1,2,2
第七種:1,1,1,2
第八種:1,1,1
第九種:1,1,2,2
第十種:1,1,2
第十一種:1,1
第十二種:1,2,2
第十三種:1,2
根據這種末尾不斷消長的特點,應該使用棧這個數據結構,算法描述:首先將元素存儲在動態數組中,對其由小到大進行排序,(爲什麼要進行排序呢,因爲和的增長幅度小於積的增長幅度,當我們發現將該元素添加到袋子裏,總和小於總積,那麼如果從小到大排列了,該元素後面的元素將都不滿足條件,就不用再做計算了,提高運算效率)首先將所有1壓入棧中(數字1能提高總和值但不會提高總積值,1的個數越多,和更有可能大於積),然後進行判斷壓棧,如果該元素加入棧中,棧中元素依然保持幸運,則將該元素壓入棧中,直到不滿足條件爲止。下一步,循環操作,循環條件是棧不爲空。如果棧不爲空,進入循環,首先判斷當前的總sum值是否大於總multy(積)值,若大於,則棧中的數字串是幸運的,計數器自加,之後彈出該幸運數字串的最後一個元素,並彈出它的下標,根據下標,繼續向後掃描數組,跳過與該元素相同的元素,再向後掃描,再一個while循環,判斷壓棧操作,如果壓入該元素後,棧中元素仍爲幸運的,則壓棧,直到數組末尾或者元素不是幸運的爲止。當棧爲空時,輸出計數器值。
代碼如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>

using namespace std;

int main(void)
{
    int n;
    cin >> n;
    vector<int> vecI;
    while(n--)
    {
        int temp;
        cin >> temp;
        vecI.push_back(temp);
    }
    sort(vecI.begin(), vecI.end());

    int cnt = 0;
    int sum = 0;
    int multy = 1;
    unsigned int i = 0;
    stack<int> sdk; // 用來存儲滿足條件的元素集合
    stack<int> lable; // 用來存儲棧中對應元素的下標
    // 先將所有的1壓入棧中
    for (; i < vecI.size() && vecI[i] == 1; ++i)
    {
        sdk.push(vecI[i]);
        lable.push(i);
        sum ++;
    }
    // 找出滿足條件的最長連續串
    while ( i < vecI.size() )
    {
        sum += vecI[i];
        multy *= vecI[i];
        if (sum > multy)
        {
            sdk.push(vecI[i]);
            lable.push(i);
        }
        else
        {
            sum -= vecI[i];
            multy /= vecI[i];
            i--;
            break;
        };
        i++;
    }
    // 當棧中元素只有一個時,也就是隻有1時,循環停止。
    while (!sdk.empty())
    {
        if (sum > multy)
        {
            // 滿足條件,開始計數,之後將滿足條件的數字串最後一個數字出棧。
            cnt ++;
            int tempI = sdk.top();
            sum -= tempI;
            multy /= tempI;
            unsigned tempLalbe = lable.top();
            sdk.pop();
            lable.pop();
            i = tempLalbe;
            // 出棧後,在繼續向後查找,將滿足條件的數字壓入棧中。
            for (;i < vecI.size() - 1 && vecI[i] == vecI[i + 1]; ++i){}; // 去掉重複的數字
            if (i < vecI.size() - 1 && vecI[i] != vecI[i] + 1)
            {
                i ++;
                while (i < vecI.size())
                {
                    sum += vecI[i];
                    multy *= vecI[i];
                    if (sum > multy)
                    {
                        sdk.push(vecI[i]);
                        lable.push(i);
                    }
                    else
                    {
                        sum -= vecI[i];
                        multy /= vecI[i];
                        i--;
                        break;
                    }
                    i++;
                }
            }
        }
        else
        {
            int tempI = sdk.top();
            sum -= tempI;
            multy /= tempI;
            unsigned tempLalbe = lable.top();
            sdk.pop();
            lable.pop();
            i = tempLalbe;
        }
    }
    cout << cnt << endl;
}

若有錯誤之處,敬請指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章