小Q是篮球训练队的教练,篮球队新加入了N名队员,第i名队员的篮球水平值为ai。
小Q现在要把他们按照以下的要求分为A队和B队进行训练:
1、A队的队员水平值之和严格大于B队的队员水平值之和
2、对于A队中的任意一名队员,如果把他分配到B队,A队的水平值之和就会严格小于B队的水平值之和。
3、每个队员必须要加入一个队伍
小Q现在想知道有多少种方案可以按照以上要求完成分队。
输入:
5 6 7 4
输出:
2
第一眼的两个思路:
使用DFS求解,不过大多笔试题都不会使用这种算法求解,通过率很低。
求出所有组合的和,组成一个数组。但是想不出动态规划的方法
本题思路:
定义一个数组,数组长度为sum(所有元素的和)+1的长度。该数组的索引为组合求和的值,数组的
将数组从大到小排序
将每一个数依次做为A中的最小值,则比这个数小的都必定在B中,对比这个数大的使用01背包进行动态规划求解。求各数相加的和等于array中的索引值的种类,再判断索引值是否满足题目题目约束的A队和B对的关系。
代码:
#include#include#includeusing namespace std;
int main() {
int n;
cin >> n;
vectora(n);
long long sum = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
sum = sum + a[i];
}
sort(a.begin(), a.end());
reverse(a.begin(), a.end());//从大到小排序
vectorarray(sum+1, 0);
array[0] = 1;
long long res = 0;
for (int i = 0; i < n; i++) {//a[i]为最小的摇摆点,所以之前的a[i]要从大到小排序
for (long long end = sum; end >= a[i]; end--) {
array[end] = array[end] + array[end - a[i]];
if ((end > sum - end) && ((end - a[i]) < (sum - end + a[i]))) {
res += array[end - a[i]];//注意这里是array[end-a[i]],以免重复计算
}
}
}
cout << res << endl;
cin >> n;
return 0;
}