题目是中文的,不解释了。
开始的时候不知道怎么可以搞出答案,就觉得这个是需要搜索的。于是就想到逐个数加上去,然后只取前m小的和,其余的弹出集合这种方法。为了可以动态维护这前m个最小的和,我用了multiset,又为了不会搜索到超出内存什么的,所以我在搜索的时候采取了剪枝,如果求和得到的数比现在集合中最大的数还要大,当前和跟之后的所有数的和都会大于集合中的最大数,这时就不用继续搜索下去了。(原始单个数的结合已进行排序)
代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cctype> 5 #include <set> 6 7 using namespace std; 8 9 typedef long long LL; 10 typedef pair<int, int> PII; 11 #define MPR make_pair 12 13 const int N = 11111; 14 multiset<PII> has; 15 int rec[N]; 16 17 int main() { 18 int T, n, m; 19 multiset<PII>::iterator cur, tmp; 20 scanf("%d", &T); 21 for (int cas = 1; cas <= T; cas++) { 22 scanf("%d%d", &n, &m); 23 has.clear(); 24 for (int i = 0; i < n; i++) { 25 scanf("%d", &rec[i]); 26 } 27 sort(rec, rec + n); // 单个元素由小到大排序 28 for (int i = 0; i < n; i++) { 29 has.insert(MPR(rec[i], i)); // 把单个元素的情况先塞进集合,PII中第一个是当前的和,第二个是当前和已经枚举到第几个元素了 30 if (has.size() > m) { // 如果超出容量,就删除最大的和 31 tmp = has.end(); 32 tmp--; 33 has.erase(tmp); 34 } 35 } 36 cur = has.begin(); 37 while (cur != has.end()) { 38 int fi = (*cur).first, se = (*cur).second; // 将和为cur.first的元素拓展,当前和最后加入的元素的下标是cur.second 39 for (int i = se + 1; i < n; i++) { 40 if (has.size() < m) { 41 has.insert(MPR(fi + rec[i], i)); 42 } else { 43 tmp = has.end(); 44 tmp--; 45 if (fi + rec[i] >= (*tmp).first) break; 46 has.insert(MPR(fi + rec[i], i)); 47 has.erase(tmp); 48 } 49 } 50 cur++; 51 } 52 tmp = has.end(); 53 tmp--; 54 printf("Case #%d: %d\n", cas, (*tmp).first); 55 } 56 return 0; 57 }
——written by Lyon