计蒜客-程序设计:轻重搭配 (贪心)(C++)
一、题目描述
n 个同学去动物园参观,原本每人都需要买一张门票,但售票处推出了一个优惠活动,一个体重为 xx 的人可以和体重至少为 2x2x 配对,这样两人只需买一张票。现在给出了 nn 个人的体重,请你计算他们最少需要买几张门票?
输入格式
第一行一个整数 nn,表示人数。
第二行 nn 个整数,每个整数 a_i 表示每个人的体重。
输出格式
一个整数,表示最少需要购买的门票数目
样例输入
6
1 9 7 3 5 5
样例输出
4
二、思路
这道题第一次思考时常见有三种思路:
1.先对输入进行从小到大排序后,从前向后遍历,例如1 3 6 7,从 1开始,3符合1的配对条件,那么1,3配对,剩下6,7两张,一共是3张票,这样做的结果是,3本来可以和6或7进行配对,而1和6,7种的另一个配对,只需两种票,可以看出,这里我们讲3这个较小的数字“浪费了”,我们并没有很合理的使用3。
2.从排序序列的首部和尾部开始配对,例如 1 3 5 7,我们将1和7进行配对,然后3和5两张票,一共三张票。这样做的结果是,7本来可以和3进行配对,然后5和1进行配对,这样也只需两张票,然后我们用7来和1进行配对,对于7这个较大的数字,我们也没有很合理的使用它,即我们“浪费了”一个较大的数字。
3.有了前面两种错误思路的经验,我们可以知道,在配对时,我们即不能浪费较小的数字,也不能浪费较大的数字,即要让较大的数字和较小的数字都能得到合理的使用。而且还有一个重要的条件时,假设一组数据中每个人都可以找到和他匹配的人,那么我们最多可以少买一般的票,也就是n/2的票,n为人数,所以先对数据从正中间进行划分,即 1 3 || 5 7,然后依次从每一段的最后面开始匹配,如果匹配成功,则同时向前一位,若不成功,则说明前面小体重的人的体重还是有一些大,不能和后面大体重的人配对,所以我们让前面的人再往前一位,知道小体重的人被遍历完。写到这里我们可以看出,只需要一个while循环即可实现上述的思路。
代码如下:
三、代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 6e5;
int n, a[N];
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++ )
cin >> a[i];
sort(a, a + n + 1);
int count = 0;
int l = n/2, r = n; // 分别从n/2 和 n开始遍历
while (l >= 1 && r >= n/2) {
if (a[r] >= 2*a[l]) { //符合
count++;
r--;
l--;
}
else
l--;
}
///
cout << n - count;
return 0;
}