面試OR筆試7——小孩分蛋糕
阿新 • • 發佈:2018-12-30
1.1 題目描述
有n塊蛋糕編號為0到n-1,有k個小孩,這k個小孩有自己喜歡的蛋糕編號(行向量),如果小孩得到自己喜歡的蛋糕就會滿意且一塊蛋糕只能給一個小孩,一個小孩只能得一塊蛋糕。求最多可以讓多少小孩滿意。
二維陣列表示n = 3,k=3,其中第一個小孩喜歡0, 1, 2編號的蛋糕,第二個喜歡1編號的,第三個喜歡2編號的。此時最多可讓3個小孩滿意。因此此時答案為3。
1.2 測試用例
1)n = 3, v= [[0, 1, 2], [1], [2]],答案為3
2)n = 6,v= [[0], [1], [2], [3], [4], [5]],答案為6
2 解答
2.1 題目分析
從蛋糕角度考慮,利用貪心演算法。由於一塊蛋糕只能給一個小孩,而一個小孩可以有很多滿意的蛋糕選擇,當一塊兒蛋糕確定所屬後,喜歡該蛋糕編號的選擇將會失效。因此為了讓更多的蛋糕被選擇,每次給出一塊兒蛋糕讓儘可能少的選擇失效。小面就是這個思路:
1)統計每塊蛋糕被多少小孩喜歡;
2)找到被最少小孩喜歡的蛋糕編號(有多個最小的選擇哪個都行,我是選擇的第一個);
3)把該蛋糕隨機分配給喜歡它的小孩,並清除該小孩喜歡的其他蛋糕編號(是指假設該小孩不喜歡其他蛋糕了),然後除該蛋糕被喜歡的人數(使之無效,也可以說該蛋糕沒有人喜歡)
4)迴圈1到3步驟,直到所有蛋糕都不被喜歡。
2.2 程式碼
int maxMeet(vector<vector<int>> &v, int n) { int vn(v.size()), ret(0); if (vn < 1) return ret; // 臨界判斷 vector<int> dm(n, 0), dv(vn,0); // dm統計某塊蛋糕被喜歡的人數, dv表示某個小孩是否滿意(1滿意) for (auto &vi : v) for (auto i : vi) if (-1 < i && i < n) ++dm[i]; // 統計 for (int mn,mk;;) { // 迴圈查詢最小並驗證是否有效 mn = vn + 1; mk = -1; for(int k1(0);k1 < n;++k1) if (0 < dm[k1] && dm[k1] < mn) { mn = dm[k1]; mk = k1; } if (mk < 0) break; mn = -1; for (int k1(0); k1 < vn && mn < 0; ++k1) { if (dv[k1]) continue; // 扎到最小, 並找到喜歡該編號的小孩 for (auto i : v[k1]) if (i == mk) { mn = k1; break; } } if (-1 < mn) { ++ret; // 分配 dm[mk] = 0; // 無效編號 dv[mn] = 1; // 該小孩已滿意 for (auto i : v[mn]) if (-1 < i && i < n) --dm[i]; // 清除該小孩喜歡的編號(假設不喜歡其他編號) } } return ret; }