科大訊飛2018暑期實習招聘線上程式設計題:如何分糖果?
題目描述:小明和小紅是好朋友,但最近遇到一個棘手的問題,有一盒糖果要分成兩份但是每顆糖果質量都不盡相同,但為了分配的公平每份糖的糖果數量相差不得超過1,在此條件下兩份糖果的質量差距儘可能小。
輸入:一行數,包含一個數n,代表糖果數量,後面一次是n個整數一次表示每個糖果的質量,每個糖果的質量都是1到450之間的一個整數,每盒最多有20個糖果。
輸出:每個樣例輸出兩個數字分別為兩堆糖果的質量,如不相同,先小後大。
樣例
輸入:5 9 6 5 8 7
輸出:17 18
一開始做這道題的時候,我糾結於“找到一個策略,按照這個策略分糖果就能得到結果”。但後來我發現,其實根本不需要找出這麼個策略,只需用暴力搜尋演算法即可。關鍵點是:“每份糖的糖果數量相差不得超過1”,假設糖果數目是n,則分成的兩堆糖果的數量一定是n/2和n-n/2。這就歸結為一個組合問題:“如何在n個糖果中選n/2個糖果,使得選出的糖果堆和剩下的糖果堆質量之差最小?”
因此,只要搜尋所有C(n,n/2)種分糖方法,就能找出差值最小的那種。
這裡重點解釋下search函式:
第一個引數sugers,表示所有糖的質量。
第二個引數weight,表示當搜尋到這一步時,已經選取出來的糖果的質量總和。
第三個引數start,表示“決定要不要選”的那顆糖果在sugers中的編號。
第四個引數count,我手裡這堆糖果中糖果的數量。如果count到達了n/2,表明搜尋到一種分法,可以進行比較了。
第五個引數res,表示“當前搜尋過的所有分法中最好的分法”,當搜尋完後,就是結果。
第六個引數target,是糖果的總重量/2。
第七個引數minchazhi,表示“當前搜尋過的所有分法中最好的分法與target的差值”,是分法好壞的依據。
最後兩個,sum是糖果的總重量,n是糖果的總數。
#include<iostream> #include<vector> #include<algorithm> #include<math.h> #include<limits.h> using namespace std; void search(const vector<int> &sugers, int weight, int start, int count, int &res,int target,int& minchazhi,int sum,int n) { //用搜索法 //我自己在糖果堆中選糖果,對於每一顆糖果,我可以選或者不選 //如果選,count+1,表示我當前手裡的糖果的數量 //每次選完,我手裡的糖果達到總數量的一半後,就進行手裡糖果重量與總質量一半的最小差值minchazhi的更新 //並記錄在當前最小差值下的我手裡糖果的質量,最後的res就是結果 if (count == n/2) { if (abs(2 * weight - sum) < minchazhi) { //這次搜尋的結果比上次更好,用res記錄這個更好的結果 res = weight; minchazhi = abs(2 * weight - sum); } } else { if (start < sugers.size()) { //還可以繼續搜尋 search(sugers,weight, start + 1, count, res, target, minchazhi, sum,n); search(sugers, weight+sugers[start], start + 1, count+1, res, target, minchazhi, sum,n); } } } int main() { int n; while (cin >> n) { vector<int> sugers(n); int sum = 0; for (int i = 0; i < n; i++) { cin >> sugers[i]; sum += sugers[i]; } int target = sum / 2; int res = 0, minchazhi = INT_MAX; search(sugers, 0, 0, 0,res,target,minchazhi,sum,n); if(res>sum-res) cout <<sum-res << ' ' << res << endl; else cout <<res << ' ' << sum-res << endl; } return 0; }