题目链接
题目描述与示例
牛牛举办了一次编程比赛,参加比赛的有3*n个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。
例如:
一个队伍三个队员的水平值分别是3,3,3.那么队伍的水平值是3
一个队伍三个队员的水平值分别是3,2,3.那么队伍的水平值是3
一个队伍三个队员的水平值分别是1,5,2.那么队伍的水平值是2
为了让比赛更有看点,牛牛想安排队伍使所有队伍的水平值总和最大。
如样例所示:
如果牛牛把6个队员划分到两个队伍
如果方案为:
team1:{1,2,5}, team2:{5,5,8}, 这时候水平值总和为7.
而如果方案为:
team1:{2,5,8}, team2:{1,5,5}, 这时候水平值总和为10.
没有比总和为10更大的方案,所以输出10.
输入描述:
输入的第一行为一个正整数n(1 ≤ n ≤ 10^5)
第二行包括3*n个整数a_i(1 ≤ a_i ≤ 10^9),表示每个参赛选手的水平值.
输出描述:
输出一个整数表示所有队伍的水平值总和最大值.
示例:
输入:
2
5 2 8 5 1 5输出:
10
解题思路
题目分析
根据题目的描述,总结下来就是需要输入一个n表示n组,输入3*n个数据表示每个队员的水平值,然后再3人一组,最后对n个组的第二大水平值进行求和即可。
个人思路
- 将3n个数据排序
- 最小的n个数必定是每组的第三水平值
- 最大的n个数必定是每组的第一水平值
- 取中间n个数求和即可
上述思路就是我看到此题目的第一反映,然后就报错了。。。。
我们拿题目数据分析:
按上述说法去头去尾取到中间的5+5=10,乍一看好像又没有问题(没错,我就是这么被骗的,然后惨遭报错)
我们换下面一组数据:
去头去尾取4+5+6=15,但是我们看这样一个分组:
取的值8+6+4=18是比我的那种更优的,斟酌思考后发现了我的问题所在:我的思路直接舍弃掉了次大的数据,使用两大带一小的取法可以让次大的数据保留下来从而提高水平值,进一步使得水平值总和更大。
正确思路:
- 将3n个数据排序
- 从第n+1个数隔1取1
ps:如上述1-9,从4开始取隔一个5取6,再隔一个7取8即可
代码展示
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
int n;
vector<int> score;
while(cin>>n)//支持循环输入
{
//设置vector的大小
score.resize(3*n);
for(int i=0;i<score.size();i++)
{
cin>>score[i];
}
//算法库中的排序算法,默认升序
sort(score.begin(),score.end());
//由于给定的分数范围1 ≤ a_i ≤ 10^9,int类型可能会超出范围导致跑不过
long long sum=0;
//前n个是最小的数据直接从第n+1个数据隔2相加(中间的那个数字是一组的最高水平)
for(int i=n;i<3*n;i+=2)
{
sum+=score[i];
}
cout<<sum;
}
return 0;
}
题解
关于我看到的题解,前面一直到排序都是基本一样,但是在选择数据的时候题解采用的方式好像又不太一样:
我的:
for(int i=n;i<3*n;i+=2)
{
sum+=score[i];
}
题解:
for(int j=0;j<n;j++)
{
sum+=score[score.size()-2*(j+1)];
}
目前我也不是很能理解这个公式的原理,后续理解了再更新一下吧。