控制变量型的多数据排序选择思想---“基于结构的排序”或叫“结构体排序”--巧克力甜蜜值题为例

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

自从ZZZZone吃完糖果后,他开始改吃巧克力了,他每天想吃n个巧克力增在甜蜜值,他决定早上吃K个巧克力,晚上吃n - K个巧克力,每个巧克力在早上吃和在晚上吃的甜蜜值是不一样的,他想让自己得到的甜蜜值最大,并想知道最大是多少。

请你编程帮助他。

输入描述:

第一行包含两个数n,K表示每天要吃的巧克力数量和要在早上吃的数量。(n <= 100000, K <= n)
第二行包含n个整数Ai(1 <= i <= n) 表示个第i个巧克力在早上吃可得到的甜蜜值 (Ai <= 100000)
第三行包含n个整数Bi(1 <= i <= n) 表示个第i个巧克力在晚上吃可得到的甜蜜值 (Bi <= 100000)

输出描述:

输出仅一行包含一个整数表示ZZZZone能获得的最大甜蜜值。

示例1

输入

2 1
3 6
2 8

输出

11

说明

早上吃第一个巧克力得到3甜蜜值,晚上吃第2个巧克力得到8的甜蜜值,所以最大可得到11的甜蜜值。

将需要保留的信息和需要进行比较的数据存在结构体数组中,对整个结构体数组按其中某一或某几个成员进行特定条件排序。---就是运用结构体排序实现类似控制变量型的多数据排序选择

一个简单的方法是,我们可以对每个巧克力计算早上和晚上吃的甜蜜值之差(diff[i] = Ai - Bi),然后按照差值从大到小排序。排序后,我们尽可能地将前k个差值最大的巧克力在早上吃掉,因为它们能带来更大的甜蜜值增量。

刚开始接触这题可能会想到:如果(diff[i]>=0)早上吃的巧克力数量还没有达到k上限,我们就继续选择差值最大(diff[i]<0)的巧克力;如果达到了上限,我们就选择剩下的巧克力在晚上吃掉。

但是如果用if分(diff[i]>=0)和(diff[i]<0)容易循环超时(反正我超时了,超在diff[i]<0时需要遍历找晚上吃的最大甜蜜值同时又不是早上已经吃了的巧克力,导致单是diff[i]<0部分就有o((n-k)*n)的时间复杂度)

下面是使用C++实现的代码:

cpp
复制代码
	#include <iostream>  

	#include <vector>  

	#include <algorithm>  

	  

	using namespace std;  

	  

	typedef pair<int, int> Chocolate; // 存储巧克力的甜蜜值和差值  

	  

	bool cmp(const Chocolate& a, const Chocolate& b) {  

	    return a.second > b.second; // 按照差值从大到小排序  

	}  

	  

	int main() {  

	    int n, k;  
        long long total_sweetness = 0;

	    cin >> n >> k;  


	    vector<Chocolate> chocolates(n);  


	    for (int i = 0; i < n; ++i) {  

	        cin >> chocolates[i].first; // 早上吃的甜蜜值  

	    }  

	  

	    vector<int> diff(n); // 存储差值  

	    for (int i = 0; i < n; ++i) {  

	        cin >> chocolates[i].second; // 晚上吃的甜蜜值  

	        diff[i] = chocolates[i].first - chocolates[i].second; // 计算差值  

	    }  

	  

	    

	    for (int i = 0; i < n; ++i) {  

	        chocolates[i].second = diff[i];  //晚上吃的甜蜜值没用了,换上差值 

	    }  

	    sort(chocolates.begin(), chocolates.end(), cmp);   // 结构体数组按照差值排序

	  

	    

	    // 尽可能地在早上吃掉差值大的巧克力  

	    for (int i = 0; i < k; ++i) {  

	        total_sweetness += chocolates[i].first; // 早上吃的甜蜜值  

	    }  

	  

	    // 剩下的巧克力在晚上吃掉  

	    for (int i = k; i < n; ++i) {  

	        total_sweetness += chocolates[i].first - chocolates[i].second; // 减去差值得到晚上吃的甜蜜值  

	    }  

	  

	    cout << total_sweetness << endl;  

	  

	    return 0;  

	}

注意:在上面的代码中,我们使用了 pair<int, int> 类型的chocolates 数组存储了巧克力的甜蜜值和差值。但是,由于我们只关心差值,并且已经计算了差值并存储在 diff 数组中,我们实际上就是要对 diff 数组进行排序,但是要保留一个早上的甜蜜值数组来跟踪原始顺序。所以,为了让diff跟差值一起动,我在一开始就使用了 pair 构建结构体数组,并在diff数组完成后将 chocolates.second 成员替换为差值,然后才开始对chocolates数组按照second成员大小排序,这就实现了diff跟差值一起动。之后就是按照题目要求的顺序要取多少就输出多少个的事儿了。

    那么如果这题不是求最大值,而是要给出哪些糖果(这些糖果的原始位置)应该在早上吃,能如何解?

    举一反三的小伙伴们就有想了,诶不是一样可以用同样结构(int,int)的结构体(.first装1-n表示糖果位置,.second装diff[i])数组表示然后还是根据 diff 数组的顺序排序chocolates数组就可以啦

    文章的最后会不会有小伙伴突发奇想说,这题如果问k值设为多少时甜蜜值最大呢?
那题目就太简单了,直接在输入b[i]时判断a[i]-b[i]>=0,k++就ok啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值