1113 Integer Set Partition (25 point(s))

Given a set of N (>1) positive integers, you are supposed to partition them into two disjoint sets A​1​​ and A​2​​ of n​1​​ and n​2​​ numbers, respectively. Let S​1​​ and S​2​​ denote the sums of all the numbers in A​1​​ and A​2​​, respectively. You are supposed to make the partition so that ∣n​1​​−n​2​​∣ is minimized first, and then ∣S​1​​−S​2​​∣ is maximized.

Input Specification:

Each input file contains one test case. For each case, the first line gives an integer N (2≤N≤10​5​​), and then N positive integers follow in the next line, separated by spaces. It is guaranteed that all the integers and their sum are less than 2​31​​.

Output Specification:

For each case, print in a line two numbers: ∣n​1​​−n​2​​∣ and ∣S​1​​−S​2​​∣, separated by exactly one space.

Sample Input 1:

10
23 8 10 99 46 2333 46 1 666 555

Sample Output 1:

0 3611

Sample Input 2:

13
110 79 218 69 3721 100 29 135 2 6 13 5188 85

Sample Output 2:

1 9359

题目大意:给你一组数据,让你分成两个集合,集合大小之差尽可能小,俩集合元素累加和之差尽可能大;

分析:

作为编程题,这是一道水题,暴力即可。输入时累加全部和得到sum,然后sort排序,累加前半部分和得到sum1,最终返回两个abs(sum-sum1-sum1)即可。

完整代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n,sum=0,sum1=0;
	cin>>n;
	vector<int>v(n);
	for(int i=0;i<n;i++){
		cin>>v[i];
		sum+=v[i];
	}
	sort(v.begin(),v.end());
	for(int i=0;i<n/2;i++){
		sum1+=v[i];
		}
	if(n%2==0) cout<<"0 "<<abs(sum-sum1-sum1);
	else cout<<"1 "<<abs(sum-sum1-sum1);
	return 0;
}

这里主要说下如何设计出一种高的划分办法。

算法思想:

将最小的 n/2 个元素放在A1,其余放在A2,分组结果即可满足题意。

仿照快排的划分思想,基于枢纽将n个元素划分为两个集合,根据划分后的枢纽所在位置i分别处理。

1)i=n / 2(向下取整),分组完成,算法结束。

2)i<n / 2,则枢纽之前的元素均属于A1集合,继续对i之后的元素进行划分。

3)i>n / 2,   则枢纽之后的元素均属于A2集合,继续对i之前的元素进行划分。

基于此算法,无需对全部元素进行排序,时间复杂度O(n),空间复杂度O(1)

核心代码实现:

int setPartition(int a[],int n){
	int pivotkey,low=0,low0=0,high=n-1,high0=n-1,k=n/2;
        bool flag=true;
	while(flag){
		pivotkey=a[low];
		while(low<high){//基于枢纽的划分 
			while(low<high && a[high]>=a[low]) high--;
			a[low]=a[high];
			while(low<high && a[low]<=a[high]) low++;
			a[high]=a[low];
		}
		a[low]=pivotkey;//枢纽放在最终位置
		if(low==k-1){ //划分成功 
			flag=false;
		}else{
			if(low<k-1){//继续划分枢纽以后的集合 
			  low0=++low;
			  high=high0;
		    }else{
			  high0=--high;
			  low=low0;
		    }
	    }
    }
    int s1=0,s2=0;
    for(int i=0;i<k;i++) sum1+=a[i];
    for(int i=k;i<n;i++) sum2+=a[i];		
    return abs(sum1-sum2); 
}

That‘s all !

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZCAIHUI_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值