题解:P12218 [蓝桥杯 2023 国 Java B] 玩具

· · 题解

这道题的话主要需要一个贪心的思想。

梳理题意

给定 2n 个整数,将它们分成 n 对,使得所有对中两数乘积的和最小。

做法介绍

先要总和最小,即代表每一对数中两数的乘积最小,那么肯定需要先对这些数进行排序。

那排序后呢?我们可以试试直接将相邻的两个数配对,这样就可以使得乘积小的一组数尽量小。但是这样过于贪心了,因为这会导致成绩大的一组也过于大。

那么我们只能折中选择一种办法:将最小的数与最大的数配对、第二小的数与第二大的数配对……以此类推,再开一个变量 ans 累加每一对中两个数的乘积即可。

贪心策略的证明

设排序后数组为 a₁≤a₂≤...≤a₂ₙ。根据排序不等式,a₁a₂ₙ + a₂a₂ₙ₋₁ + ... + aₙaₙ₊₁ ≤ 其他任何配对方式的和。

代码实现

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,a[N*2];//有2n个数 
int ans=0;
signed main(){
    cin>>n;
    n*=2;//把n翻倍 
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);//从小到大排序(从大到小排序也行) 
    for(int i=1,j=n;i<=j;i++,j--) ans=ans+(a[i]*a[j]);//将最小的数与最大的数配对、第二小的数与第二大的数……两两配对累加起来 
    cout<<ans;
    return 0;
}