OJ_数组划分

题干

在这里插入图片描述

C++实现——复杂度极高的深度优先遍历(容易超时)

#include <iostream>
#include <vector>
using namespace std;

//sa+sb = sum
//sb-sa = diff

int sum = 0;
int diff = 0;

void DFSFindMinDiff(vector<int> &arr,int pos,int sa) { //sa表示a集合的元素和
    if(pos == arr.size()) {
        return;
    }
    //arr[pos]不放入a集合
    DFSFindMinDiff(arr,pos+1,sa);

    //arr[pos]放入a集合
    int newdiff;//记录当前差值
    if(2*(sa+arr[pos]) - sum > 0) {//sa>sb
        newdiff = 2*(sa+arr[pos]) - sum;
    } else {//sa<sb
        newdiff = sum - 2*(sa+arr[pos]);
    }
    if(newdiff < diff) {
        diff = newdiff;
    }
    DFSFindMinDiff(arr,pos+1,sa+arr[pos]);
}

int main() {
    vector<int> arr;
    int i;
    //EOF对应键盘的ctrl+c
    while(scanf("%d",&i) != EOF) {
        arr.push_back(i);
    }
    for(int i = 0; i<arr.size(); ++i) {
        sum+=arr[i];
    }
    diff = sum;//一开始,a集合一个元素也没有,全都在b集合中
    DFSFindMinDiff(arr,0,0);

    int sa = (sum-diff)/2;
    int sb = sa+diff;//sa更小
    printf("%d %d\n",sb,sa);
    return 0;
}

C++实现——优化策略(剪枝)

  • arr排序,从大到小
  • 先执行加入arr[pos],再执行不加入的
  • 一开始sa<sb,某个时刻sa>sb,就可以终止了
  • 当diff=1时,可以提前终止
  • 当arr[pos] > sum/2时,可以终止
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int sum = 0;//sa+sb = sum
int diff = 0;//sb-sa = diff
bool exitFlag = false;//用来记录是否提前退出
bool compare(int lhs,int rhs){
    return lhs>rhs;
}

void DFSFindMinDiff(vector<int> &arr,int pos,int sa) { //sa表示a集合的元素和
    if(pos == arr.size() || exitFlag == true) {
        return;
    }

    //arr[pos]放入a集合
    int newdiff;//记录当前差值
    if(2*(sa+arr[pos]) - sum > 0) {//sa>sb
        newdiff = 2*(sa+arr[pos]) - sum;
    } else {//sa<sb
        newdiff = sum - 2*(sa+arr[pos]);
    }
    if(newdiff < diff) {
        diff = newdiff;
        if(diff == 0||diff==1||2 * arr[pos] > sum){//这三种情况,可提前终止
            exitFlag = true;
        }
    }

    if(2*(sa+arr[pos]) - sum < 0){
        DFSFindMinDiff(arr,pos+1,sa+arr[pos]);
    }

    //arr[pos]不放入a集合
    DFSFindMinDiff(arr,pos+1,sa);
}

int main() {
    vector<int> arr;
    int i;
    //EOF对应键盘的ctrl+c
    while(scanf("%d",&i) != EOF) {
        arr.push_back(i);
    }
    for(int i = 0; i<arr.size(); ++i) {
        sum+=arr[i];
    }
    diff = sum;//一开始,a集合一个元素也没有,全都在b集合中

    sort(arr.begin(),arr.end(),compare);//先从大到小排序

    DFSFindMinDiff(arr,0,0);

    int sa = (sum-diff)/2;
    int sb = sa+diff;//sa更小
    printf("%d %d\n",sb,sa);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值