题目
设S是n(n为偶数)个不等的正整数的集合,要求将集合S划分为子集S1和S2,
使得|S1|=|S2|=n/2,且两个子集元素之和的差达到最大。
思路
根据题目要求,将数组分为相同长度的两部分,让他们之差最大,朴素做法可以排序,对于有序数列后一半之和减去前一半之和一定最大,但排序算法平均复杂度普遍在O(nlogn),还能继续对其优化。其实我们不需要将全部数组排序,只要将数组分成小于中位数和大于中位数两部分即可,关键在于找出中位数,而找出某个数的位置正是快速排序的核心思想。
下面为一次迭代过程
最终4位于数组正确的位置(即其左边都小于4,右边都大于4)。
回到本题,如果碰到数在数组中间位置,直接结束递归即可,此数前后两部分即为所求答案。
代码
#include <iostream>
using namespace std;
int n;
int cnt = 0;
bool flag = false;
void Rarr(int arr[], int len, int minn, int maxn) {
srand(time(0));
for (int i = 0; i < len; i++) {
arr[i] = minn + rand() % (maxn - minn + 1);
}
}
void QuickSort(int arr[], int low, int high) {
int i = low;
int j = high;
if (i >= j||flag) {
return;
}
cnt++;
int temp = arr[low];
while (i != j) {
while (arr[j] >= temp && i < j) {
j--;
}
while (arr[i] <= temp && i < j) {
i++;
}
if (i < j) {
swap(arr[i], arr[j]);
}
}
swap(arr[low], arr[i]);
if (i == n / 2 - 1 || i == n / 2)
{
flag=true;
return;
}
QuickSort(arr, low, i - 1);
QuickSort(arr, i + 1, high);
}
int main() {
cin >> n;
int *arr=new int[n];
//Rarr(arr, n, 1, 100); //生成随机数组
for (int i = 0; i < n; i++){ //手动输入数组
cin >> arr[i];
}
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
QuickSort(arr, 0, n - 1);
for (int i = 0; i < n/2; i++)
{
cout << arr[i] << ' ';
}
cout << endl;
for (int i = n / 2; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << cnt;
}