UVA 1149 Bin Packing

传送门

A set of n 1-dimensional items have to be packed in identical bins. All bins have exactly the same length l and each item i has length li l. We look for a minimal number of bins q such that

   • each bin contains at most 2 items,

  • each item is packed in one of the q bins,

  • the sum of the lengths of the items packed in a bin does not exceed l.

You are requested, given the integer values n, l, l1, . . . , ln, to compute the optimal number of bins q.

Input

The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs. The first line of the input file contains the number of items n (1 ≤ n ≤ 10^5 ). The second line contains one integer that corresponds to the bin length l ≤ 10000. We then have n lines containing one integer value that represents the length of the items.

Output

For each test case, your program has to write the minimal number of bins required to pack all items.

The outputs of two consecutive cases will be separated by a blank line.

Note: The sample instance and an optimal solution is shown in the figure below. Items are numbered from 1 to 10 according to the input order.

Sample Input

1

10

80

70

15

30

35

10

80

20

35

10

30

Sample Output

6

------------------------------------------------

首先注意输出格式,UVA的题常常要求The outputs of two consecutive cases will be separated by a blank line.巨坑。

Solution:

Greedy,我的解法是从小到大枚举长度,将每个长度与另一个尽可能大的长度装在一起,若找不到就将这个长度单独装。

Proof:

反证法。假设存在一种的方案,其中某个装有两个物品i, j (设length(i)<=length(j))的容器b中的较短的那个物品i不是与能和它装在一起的最长物品k装在一起的,调换kj的位置,得到的是同样优的方案。所以上述贪心策略导致最优方案。

Implementation:

实现是用map模拟,太low了。

#include <bits/stdc++.h>
using namespace std;
map<int,int> cnt;
int main(){
    int T; scanf("%d", &T);
    for(int n, l, cs=0; T--;){
        if(cs++) puts("");
        scanf("%d%d", &n, &l);
        for(int len; n--;) scanf("%d", &len), cnt[len]++;
        int ans=0;
        for(int now; !cnt.empty();){
            now=cnt.begin()->first;
            ans++;
            cnt.begin()->second--;
            if(!cnt.begin()->second){
                cnt.erase(now);
            }  
            if(cnt.empty()) break;
            auto it=cnt.lower_bound(l-now);
            if(it==cnt.end()) it--;
            for(;;it--){
                if(it->first<=l-now){
                    it->second--; 
                    if(!it->second){
                        cnt.erase(it->first);
                    }
                    break;
                }
                if(it==cnt.begin()) break;
            }
        }
        printf("%d\n", ans);
    }
}

P.S. 我本想用multiset模拟的,但后来发现multiset不支持单个删除相同元素

multiset<int> s;
int main(){
    s.insert(10);
    s.insert(10);
    printf("%d\n", s.size());    //2
    s.erase(10);
    printf("%d\n", s.size());    //0
}

 

posted @ 2015-09-27 21:45  Pat  阅读(349)  评论(0编辑  收藏  举报