(笔试题)将数组分成两组,使两组的和的差的绝对值最小

题目:

数组中的数分为两组,给出一个算法,使得两个组的和的差的绝对值最小数组中的数的取值范围是0<x<100,元素个数也是大于0,小于100
比如a[]={2,4,5,6,7},得出的两组数{2,4,,6}和{5,7},abs(sum(a1)-sum(a2))=0; 
比如{2,5,6,10},abs(sum(2,10)-sum(5,6))=1,所以得出的两组数分别为{2,10}和{5,,6}。

思路:

初看问题,感觉好像是个组合问题,通过暴力穷举解决问题。

但仔细想想,问题可以转换成,从数组中找出一组数据,使之尽可能等于数组和的一半。

这样一来是不是有点类似于0-1背包呢?是的,就是0-1背包问题。

条件:数组中的数就是背包问题的weight值,数组中的数也是背包问题的value值,即二者一样。

问题:背包里装哪些物品,使得其价值之和最接近总价值的一半。

于是通过背包问题来解决这道题就显得很简单了,下面简单陈述通过动态规划来求解0-1背包问题的思路。

假设V[i][j]表示从i件物品中选出重量为j的物品的最大价值,weight[i],value[i]分别代表第i件物品的重量和价值(在题目中,weight、value属于同一数组)。

动态转移方程为:

V[i][j]=V[i-1][j]  if j<weight[i]

V[i][j]=max(V[i-1][j],V[i-1][j-weight[i]]+value[i]) if j>weight[i]

另外,如果想知道是由那几件物品组成的最大价值,可以从后往前回溯,当V[i][j]>V[i-1][j],说明第i件物品被加入(路径不唯一)。

代码:

#include <iostream>
#include <vector>

using namespace std;

int knapSack(int num,int C,const vector<int> weight,const vector<int> value,vector<int> &x);

int main()
{
    int w[]={2,4,5,6,7};
    int v[]={2,4,5,6,7};
    int num=sizeof(w)/sizeof(w[0]);
    vector<int> weight(w,w+num);
    vector<int> value(v,v+num);
    int C=12;
    vector<int> x(num);

    int total=knapSack(num,C,weight,value,x);
    cout<<"Total weight is "<<total<<endl;

    return 0;
}

int knapSack(int num,int C,const vector<int> weight,const vector<int> value,vector<int> &x){
    vector<vector<int> > V(num+1,vector<int>(C+1));
    for(int i=1;i<=num;i++){
        for(int j=1;j<=C;j++){
            if(j<weight[i-1])
                V[i][j]=V[i-1][j];
            else
                V[i][j]=max(V[i-1][j],V[i-1][j-weight[i-1]]+value[i-1]);
        }
    }

    cout<<"Dynamic Matrix: "<<endl;
    for(int i=1;i<=num;i++){
        for(int j=1;j<=C;j++){
            cout<<V[i][j]<<" ";
        }
        cout<<endl;
    }

    int j=C;
    for(int i=num;i>0;i--){
        if(V[i][j]>V[i-1][j]){
            x[i]=1;
            j=j-weight[i-1];
        }
        else
            x[i]=0;
    }

    cout<<"The articles chosen is: "<<endl;
    for(int i=0;i<num;i++){
        if(x[i])
            cout<<i+1<<" ";
    }
    cout<<endl;

    return V[num][C];
}

运行结果:

时间: 2024-08-07 16:59:01

(笔试题)将数组分成两组,使两组的和的差的绝对值最小的相关文章

数组:正整数数组分成2组使其和的差的绝对值最小

[问题描述] 把正整数数组 a[N] 中的N个元素任意划分成2部分,使得这2部分和的差的绝对值最小. [算法思路] 问题可转换成,从数组中找出一组数据,使之尽可能等于数组和sum的一半.那么必然有他一半的和是 <= sum/2,接下来用0-1背包问题来解! 现在数组元素即物品,元素值即使是背包问题中的物品weight,也是物品的value,即二者一样,背包容量C = sum/2.问题就是现在满足背包容量情况下,装哪些物品,使得其价值之和最大. [代码] 参见本博客的 "DP:0-1背包问题

数组中两个元素差的绝对值最小

#include <stdio.h> #include <stdlib.h> /* 给定一个含有n个元素的整型数组, 找出数组中的两个元素x和y使得abs(x - y)值最小 */ /* 思路: 排序, 然后遍历数组比较相邻值相减得到的值 */ typedef struct{ int num1; int num2; }TwoNumber; TwoNumber getTNumber(int* numbers, int length); int cmp(const void *a,co

(笔试题)数组A中任意两个相邻元素大小相差1,在其中查找某个数。

题目: 数组A中任意两个相邻元素大小相差1,现给定这样的数组A和目标整数t,找出t在数组A中的位置.如数组:[1,2,3,4,3,4,5,6,5],找到4在数组中的位置. 思路: 很明显,在数组中寻找某个数的复杂度为O(n),但在某些特殊数组中,可以通过寻找规律来减少比较次数. 上述数组的规律就是:相邻元素相差1,奇偶交替排列. 如果某个数A[i]等于要查找的数x,那么由于奇偶交替排列的关系,可以跳过下个数A[i+1],即i=i+2: 如果某个数A[i]不等于要查找的数x,那么由于相邻元素相差1

Ebay 面试题 | 把数组分成和大小一样的集合

题目描述 cs3k.com 给定一个只包含正整数的非空数组,判断该数组能否分成两个和相等的子数组. 样例输入 cs3k.com 输入[1,5,11,5] 返回 true . 可以分为[1,5,5]和[11]输入[1,2,3,5]    返回false. 无法分为相等的两个子数组 算法分析 本题需要判断数组能否分为两个和想等的子数组,等价于在数组中选取一定数目的元素,能否使得选择的元素之和为sum/2(sum为数组中所有元素的和).而等价的问题就是经典的0-1背包问题,即给定一个正整数数组,能否从

58同城笔试题:数组去重;分饼干(分糖果);最小路径和(leetcode64)

1. 数组去重 题目描述 /** * 有序数组去重 * 输出最终的数字个数 * 输入:1,2,2 * 输出:2 * @author Turing * */ 代码 import java.util.*; public class E { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String[] str = sc.nextLine().split(","); int len

将1、2、3、……、81这八十一个连续自然数分成三组,使每组的和相等。三组中个数最多的一组有几个?

1 <script type="text/javascript"> 2 window.onload = function() { 3 var n =81; 4 // 求组数 5 var zushu = Math.floor(n / 2); 6 var sum = (1 + 81) * (zushu) + (zushu + 1) * (n % 2); 7 console.log("总和为:" + sum); 8 var avg = sum / 3; 9 c

(笔试题)不用除法操作符,实现两个整数的除法

题目: 如题所示 思路: 与上一题要求不一样的是,这里是整数的除法,而不仅仅是正整数,因此需要对输入的两个数的正负性进行判断 代码: #include <iostream> using namespace std; int myDiv(int a,int b){ if(a==0) return 0; if(a==b) return 1; if(b==1) return a; bool sign=true; // indicate +/-1 int ans=0; // a>0,b<0

腾讯2016年实习生笔试题-蛇形数组-循环枚举遍历

在n*n方阵里填入1,2···,n*n,要求天成蛇形,如n=4时. 10  11  12      1 9   16   13     2 8   15   14     3 7     6    5     4

(笔试题)不用除法操作符,实现两个正整数的除法

题目: 如题所示 思路: 假设问题是a除以b: 题目要求是正整数,所以考虑的条件不是很多,如果要求是整数的话,即要考虑正负情况的判断. 1.最简单的就是依次用被除数a减去除数b,并统计减去的次数,即为相除结果: 这种方法效率不高,尤其是在被除数a很大,除数b很小的情况下,效率非常低: 2.考虑每次相减时,将b翻倍,这样就可以提高很大的效率: 3.考虑位运算,因为位运算一般都比较高效: 4.采用递归的方法: 代码: 注意:代码中没有考虑b=0的判断 #include <iostream> usi