2019阿里暑期實習筆試編程題

阿里的筆試,怎麼說呢,感覺挺難的,選擇會個一半,編程題也只寫了一題,是我看不懂題目,第一題調試了半小時,一個小時寫兩道,這一刻感覺自己編程太菜了,得好好練,刷刷題纔行。直接上題目吧。

1、小明是一個數學家,他喜歡用數字給事物命名編號,他給自己編號爲1,同時在2019年小明開辦了一個農場,準備開始養母豬,他專門給農場的母豬用以下數列2,3,4,5,7,9,12,16,21,28,37,49,65,86,114,151...進行命名。假設農場的母豬永遠不會死,小母豬出生後3年後成熟,成熟後從第三年開始每年只會生一隻小母豬。第一年農場,有一隻剛剛出生的小母豬和一隻成熟的母豬(本年不再生小豬,下一年開始生小豬),並給他們編號爲2和3。請問,第m只母豬編號爲多少?其是哪一年出生的?小明還準備了1份禮物,專門頒給農場第1到m只的母豬頒獎,頒獎規則如下:選出第1到m只的母豬翻轉編號(114編號翻轉爲411)爲第k大的母豬進行頒獎,請問是第幾只豬獲獎?提示: f(n)=f(n-2)+f(n-3)

我先說下這題的解決思路:

(1)求num,f(n)=f(n-2)+f(n-3)

(2)母豬什麼時候要生小豬,而且每隻成熟母豬一年只能生一隻小豬

(3)取1-m只小豬,對小豬按num反轉進行排序

爲了解決上述問題,可以定義一個類,根據題意,可以提取的屬性有:出生序號1-m,出生年份born,規則編號num,以及年齡old。於是構建如下類:

    static class Pig{
        public int index;//出生序號
        public int born;//出生年份
        public int num;//規則序號
        public int old;//年齡
        public Pig(int index,int born,int num,int old){
            this.index = index;
            this.born = born;
            this.num = num;
            this.old = old;
        }

        @Override
        public String toString() {
            return "Pig{" +
                    "index=" + index +
                    ", born=" + born +
                    ", num=" + num +
                    ", old=" + old +
                    '}';
        }
    }

接着求解求f(n)=f(n-2)+f(n-3),用動態規劃,狀態轉移方程很簡單就是res[i]=res[i-2]+res[i-3]:

    public static int getNum(int n){//動態規劃求num
        if(n + 1 < 5)return n + 1;
        int res[] = new int[n + 1];
        res[0] = 1;
        res[1] = 2;
        res[2] = 3;
        res[3] = 4;
        for(int i=4;i<n+1;i++){
            res[i] = res[i-2] + res[i-3];//狀態轉移方程
        }
        return res[n];
    }

由於編號小明是1,故第n+1個編號纔是第n只豬的編號。

對1-m只小豬按num反轉排序,即對小於等於num的所有小豬,先反轉num,再按num排序,然後求第k大:

    public static int getRewardNum(List<Pig> pigList, int numM, int k){
        List<Pig> list = new ArrayList<>();
        //求第一到第m只豬,並把num反轉
        for(Pig pig: pigList) if(pig.num <= numM) list.add(new Pig(pig.index,pig.born,Integer.parseInt(new StringBuilder(pig.num+"").reverse().toString()),pig.old));
        list.sort(((o1, o2) -> Integer.compare(o1.num,o2.num)));//根據num排序
        if(k<0||k>list.size())return 0;//k不合法直接返回0
        return list.get(list.size() - k).index;//返回第k大的出生序號
    }

爲什麼前面我說看不懂題目,調試半天,就是在這:

假設農場的母豬永遠不會死,小母豬出生後3年後成熟,成熟後從第三年開始每年只會生一隻小母豬。

到底是小豬出生時old賦值0還是1,到底是old大於等於3(成熟了馬上能生小豬)就能生小豬,還是大於3(成熟一年後)才能生小豬,也許我語文太差,我真的不明白,於是怎麼調試born都出不來,後面只能強行“縮短”長成熟的時間,於是old初始賦值1,old大於等於3就能生小豬。我擦,竟然通過了,這期間花了我20分鐘調試。

    public static List<Pig> getPigList(int m){//得到第m只豬出生時的所有豬
        List<Pig> pigList = new ArrayList<>();
        int curYear = 2019;
        pigList.add(new Pig(1,curYear,getNum(1),3));//第一隻成熟母豬
        pigList.add(new Pig(2,curYear,getNum(2),1));//第一隻小母豬
        int startIndex = 3;
        int targetNum = getNum(m);
        while ( pigList.get(pigList.size()-1).num <= targetNum){
            List<Pig> youngPigList = new ArrayList<>();
            curYear++;
            int lastNumPig = pigList.size();
            for(int i=0;i<pigList.size();i++){
                pigList.get(i).old++;//年齡加1
                if(pigList.get(i).old>=3)//可以生小豬了
                    youngPigList.add(new Pig(startIndex++,curYear,getNum(lastNumPig++ + 1),1));
            }
            for (Pig p:youngPigList) pigList.add(p);
        }
        for (Pig p:pigList) System.out.println(p);
        return pigList;
    }

main方法:

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String strs[] = sc.nextLine().split(",");
        int m = Integer.parseInt(strs[0]), k = Integer.parseInt(strs[1]);
        List<Pig> pigList = getPigList(m);
        Pig targetPig = pigList.get(m-1);
        System.out.printf("%d,%d,%d\n",targetPig.num,targetPig.born,getRewardNum(pigList,targetPig.num,k));
        sc.close();
    }

調試結果:

2、小明在雙十一晚會上抽獎贏得了一次天貓超市免單的機會,享受在一個包裹內最大體積V,最大重量M內免單
假設商品i,體積Vi,重量Mi,庫存Si,價格Pi目前天貓超市的商品分爲生鮮水產(1)、食品酒水(2),美妝個護(3),居家生活(4)四大類
生鮮水產不與美妝個護同包裹請你幫助小明在購物車裏添置商品使得總價值最大 。

按一個小時來說,第一題調試花了很多時間,第二題根本沒時間寫,後面看,根本不會寫,就有回溯的想法,用HashMap記錄出現過的序列,後面發現,每個滿足的序列長度不定長,所以懵了。總結,被安排得明明白白,以後要多多練習纔行。

 

這用例的答案奇怪,如果說總體積v,總重量w以內是包含的話,應該是這麼算:

第3種物品取5個得到v=15,w = 20, s = 1, p = 25, 然後在第2種物品中再取一個此時v=28,w = 30,p = 36。

如果是不包含的話應該是這麼算:

第2種物品取2個得到v=26,w = 20, s = 10, p = 22, 然後在第3種物品中再取2個此時v=32,w = 28,p = 32。

兩種情況都不可能算得33啊,不知道是不是我理解錯了,我的參考代碼:

#include<iostream>
#include<vector>
using namespace std;
struct good
{
    int v, w, p, t;
};
int alibishi3(int N, int V, int W, vector<good>& goods){
    vector<vector<int>> f(60, vector<int>(60, 0));
    for(auto g : goods){
        for (int j = V; j >= g.v; j--)
        {
            for (int k = W; k >= g.w; k--)
            {
                f[j][k] = max( f[j][k], f[j - g.v][k - g.w] + g.p);
            }
        }
        
    }
    return f[V][W];    
}

int main()
{
    int N,V,W;  
    cin >> N >> V >> W;
    
    vector<good> goods;
    for(int i = 0; i < N; i++){
        int v, w, s, p, t;
        cin >> v >> w >> s >> p >> t;
        for (int k = 1; k <= s; k *= 2){
            s -= k;
            goods.push_back({k * v, k * w, k * p, t});
        }
        if(s > 0) goods.push_back({s * v, s * w, s * p, t});
    }
    vector<good> goods1;//不包含種類3的
    vector<good> goods3;//不包含種類1的
    for(auto g : goods)
        if(g.t == 1)goods1.push_back(g);
        else if(g.t == 3)goods3.push_back(g);
        else goods1.push_back(g), goods3.push_back(g);
    int res = max(alibishi3(N,V,W,goods1), alibishi3(N,V,W,goods3));
    cout << res << endl;
    system("pause");
    return 0;
}

 

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