1. 程式人生 > >面試OR筆試7——小孩分蛋糕

面試OR筆試7——小孩分蛋糕

1.1 題目描述

n塊蛋糕編號為0n-1,有k個小孩,這k個小孩有自己喜歡的蛋糕編號(行向量),如果小孩得到自己喜歡的蛋糕就會滿意且一塊蛋糕只能給一個小孩,一個小孩只能得一塊蛋糕。求最多可以讓多少小孩滿意。

二維陣列表示n = 3k=3,其中第一個小孩喜歡0, 1, 2編號的蛋糕,第二個喜歡1編號的,第三個喜歡2編號的。此時最多可讓3個小孩滿意。因此此時答案為3

1.2 測試用例

1n = 3, v= [[0, 1, 2], [1], [2]],答案為3

2n = 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;
}




3 測試

驗證均正確。