• 1113 Integer Set Partition (25 分)


    水~。

    题意

    给定一个由整数组成的集合,集合中的整数各不相同,现在要将它分为两个子集合,使得这两个子集合的并为原集合、交为空集,同时在两个子集合的元素个数n1与n2之差的绝对值|n1-n2|尽可能小的前提下,要求它们各自的元素之和S1与S2之差的绝对值|S1-S2|尽可能大。

    思路

    首先可以注意到,由于需要先满足两个子集合的元素个数n1与n2之差的绝对值|n1-n2|尽可能小,因此可以知道当原集合中元素个数N为偶数时,两个子集合中的元素个数相同,此时两个子集合的元素个数n1与n2之差的绝对值|n1-n2|为0;而当原集合中元素个数N为奇数时,两个子集合的元素个数n1与n2之差的绝对值|n1-n2|为1,考虑到需要让两个子集合各自的元素之和S1与S2之差的绝对值|S1-S2|尽可能大,因此应该让尽可能多、尽可能大的元素都分配到其中一个子集合中。

    由此可以得到最简洁的做法:即把所有元素从小到大排序,然后将较小的N/2(向下取整)个元素作为其中一个集合,而让剩下的元素作为另一个集合,这样就能得到最大的元素和之差,这种做法的时间复杂度为(O(NlogN))

    由于本题的数据范围较小,因此上面的做法是可以通过的,而如果数据范围非常大,那么就有可能超时。此时需要通过快速选择算法找出元素第N/2大,同时根据这个元素把序列分成小于和大于两部分即可。但是同样由于本题数据范围较小,使得rand版本的快速选择算法虽然时间复杂度为(O(N)),但其实际效果并不好(rand函数、递归的时间开销都不能忽视),反而会在本题的时间限制下超时。

    因此下面介绍一个非常有用的替代函数:nth_element,nth_element函数在头文件algorithm中,需要同时添加“using namespace std;”才能使用,这个函数可以找到序列第K大并把序列分成小于跟大于两部分,也就是说我们可以直接用这个函数来代替随机选择算法,效率颇高。对一个数组a,nth_element(a,a+K,a+N)就是把序列切分成a[0...(K-1)]和a[K...(N-1)]两部分,所以序列第N/2大就可以用nth_element(a,a+N/2,a+N)实现。

    代码

    直接排序:

    const int N=1e5+10;
    int a[N];
    int n;
    
    int main()
    {
        cin>>n;
    
        for(int i=0;i<n;i++) cin>>a[i];
    
        sort(a,a+n);
    
        int lsum=0,rsum=0;
        int mid=a[(n-1)/2];
        for(int i=0,j=n-1;i<j;i++,j--)
        {
            lsum+=a[i];
            rsum+=a[j];
        }
        if(n & 1)
            cout<<1<<' '<<rsum+mid-lsum<<endl;
        else
            cout<<0<<' '<<rsum-lsum<<endl;
        //system("pause");
        return 0;
    }
    

    快速选择算法:

    const int N=1e5+10;
    int a[N];
    int n;
    
    int main()
    {
        cin>>n;
    
        for(int i=0;i<n;i++) cin>>a[i];
    
        nth_element(a,a+n/2,a+n);
    
        int lsum=0,rsum=0;
        for(int i=0;i<n/2;i++) lsum+=a[i];
        for(int i=n/2;i<n;i++) rsum+=a[i];
    
        cout<<n%2<<' '<<rsum-lsum<<endl;
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    c语言字符串_续
    c语言中文件的操作
    Linux基础知识
    netstat
    wireshark 过滤规则
    常用cmd命令
    优化过的redis封装类
    二十三岁,新的起点
    计划看的书目
    [转载]爱上一个给予你正能量的人
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14419760.html
Copyright © 2020-2023  润新知