如何将整数数组划分为2个子数组并使它们的平均值相等?

时间:2011-03-14 07:29:19

标签: algorithm

请帮助我解决上述问题。将会感谢具有工作示例的算法。此外,如果无法解决上述问题,请处理此案。

好的,我到现在所拥有的是以下内容:

遍历整个数组并获得整个数组的平均值。上)。让我们称之为平均

然后从这个平均值得到除a[0]之外的整个数组的平均值(公式为:avg(a[1..n-1])=(avg(a[0..n-1])*n-a[0])/(n-1))。然后你取这个新的平均值并将其与[0]进行比较。如果它们不相等,则使用上面的公式移动到下一个计算平均值的平均值。

虽然有人为我提供了“有效”的解决方案,但我正在寻找最有效的实施方案。

6 个答案:

答案 0 :(得分:2)

快速谷歌搜索返回this。在任何情况下,如果您不是在寻找性能,backtracking始终是一个选项

编辑: 我试图应用回溯。我的解决方案绝无效率。当然,您可以替换平均方法以避免其他级别的骑行。此外,为了表明没有解决方案,您只需计算解决方案的数量。

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class SOQuestion {

    /**
     * just prints a solution
     * 
     * @param list
     * @param indexes
     */
    public static void printSolution(List list, HashSet indexes) {
        Iterator iter = indexes.iterator();
        while (iter.hasNext()) {
            System.out.print(list.get((Integer) iter.next()) + " ");
        }
        System.out.println();
    }

    /**
     * calculates the average of a list, but only taking into account the values
     * of at the given indexes
     * 
     * @param list
     * @param indexes
     * @return
     */
    public static float avg(List list, HashSet indexes) {
        Iterator iter = indexes.iterator();
        float sum = 0;
        while (iter.hasNext()) {
            sum += (Integer) list.get((Integer) iter.next());
        }
        return sum / indexes.size();
    }

    /**
     * calculates the average of a list, ignoring the values of at the given
     * indexes
     * 
     * @param list
     * @param indexes
     * @return
     */
    public static float avg_e(List list, HashSet indexes) {
        float sum = 0;
        for (int i = 0; i < list.size(); i++) {
            if (!indexes.contains(i)) {
                sum += (Integer) list.get(i);
            }
        }
        return sum / (list.size() - indexes.size());
    }

    public static void backtrack(List list, int start, HashSet indexes) {
        for (int i = start; i < list.size(); i++) {
            indexes.add(i);
            if (avg(list, indexes) == avg_e(list, indexes)) {
                System.out.println("Solution found!");
                printSolution(list, indexes);
            }
            backtrack(list, i + 1, indexes);
            indexes.remove(i);
        }
    }

    public static void main(String[] args) {
        List test = new ArrayList();
        test.add(2);
        test.add(1);
        test.add(3);

        backtrack(test, 0, new HashSet());
    }
}

答案 1 :(得分:0)

我是怎么做到的:
1 - 总阵列 - &gt;如果是奇数,则无法创建两个单独的数组。为O(n)
2 - 除以2 3 - 排序数组(从最高到最低) - &gt; O(NLogN)
4 - 从最高编号开始,并继续尝试通过转到下一个最高编号来获得剩余金额。如果你不能这样做,那么将数字移动到另一个数组。 - &GT;我认为最坏的情况是O(N ^ 2)。

所以让我们举个例子: 3,19,7,4,6​​,40,25,8

  1. 总计= 112
  2. 除以2 = 56
  3. 排序数组 - 3,4,6,7,8,19,25,40
  4. - &GT;列表1中的40个(列表1总计= 40,剩余16个)
    - &GT; 25个太大,在列表2中(列表2总计= 25)
    - &GT; 19列表太大,列表2(列表2总计= 44)
    - &GT;在列表1中测试8(列表1总计= 48,剩余8个)
    - &GT;列表1中的测试7(列表1总计= 55,剩余1个)
    - &GT;无法再添加1个 - &GT; 7未通过测试6(列表1总计= 54,剩余2个)
    - &GT;无法再添加2个 - &GT; 6未通过测试4(总共2个 - 52个,剩下4个)
    - &GT;无法再添加2个 - &GT; 4未通过测试3
    - &GT; 3失败回到8 - &GT;将8移动到列表2并开始测试7(列表1总计= 47,9剩余,列表2总计= 52)
    - &GT;测试6(列表1总计= 53,剩余3个)
    - &GT;添加3个元素(列表1总计= 56,成功)
  5. 所以这两个清单是[40,7,6,3]和[25,19,8,4]

答案 2 :(得分:0)

试试这段代码......

#include <QList>
#include <QDebug>

/****

We sort the array in the desending order. So the first two elemnts
are the biggest element of the array. These are put in split1 and the
split2 array. Note that we start from the biggest element the average
is going to be much higher than the final avarage. Next we start placing
the smaller elemnts from source to split1 or split2. To do this we make a
simple dicision. We look at the value to be added and then see if that will
increase/decrease the average of a given split. Accordingly we make our
decesion.

****/


static bool averageSplit(const QList<int>& source,
                         QList<int>& split1,
                         QList<int>& split2)
{
    if (source.size() < 2) {
        return false;
    }

    QList<int> list = source;
    qSort(list.begin(), list.end(), qGreater<int>());

    double sum = 0;
    foreach(int elm, list) {
        sum += elm;
    }
    const double totalAvg = sum / list.size();

    double sum1 = list[0];
    double sum2 = list[1];
    split1.append(list[0]);
    split2.append(list[1]);
    for(int i = list.size() - 1; i >= 2; --i) {
        double avg1 = sum1 / split1.size();
        double avg2 = sum2 / split2.size();
        int val = list[i];
        if (avg1 < avg2) {
            // Try to increase tha avg1 or decrease avg2.
            if (val > split1.size()) {
                split1.append(val);
                sum1 += val;
            }
            else {
                split2.append(val);
                sum2 += val;
            }
        }
        else {
            // Try to increase tha avg2 or decrease avg1.
            if (val > split2.size()) {
                split2.append(val);
                sum2 += val;
            }
            else {
                split1.append(val);
                sum1 += val;
            }
        }
    }

    qDebug() << "totalAvg " << totalAvg;
    qDebug() << "Avg1 " << sum1 / split1.size();
    qDebug() << "Avg2 " << sum2 / split2.size();
}

void testAverageSplit()
{
    QList<int> list;

    list << 100 << 20 << 13 << 12 << 12 << 10 << 9 << 8 << 6 << 3 << 2 << 0;
    list << -1 << -1 << -4 << -100;

    QList<int> split1;
    QList<int> split2;
    averageSplit(list, split1, split2);

    qDebug() << "split1" << split1;
    qDebug() << "split2" << split2;
}

答案 3 :(得分:0)

我认为如果原始数组中所有元素的SUM都是奇数,那么就不可能分成2个数组。 如果sum == even,你可以开始制作你的数组,使得每个元素的总和== SUM / 2

答案 4 :(得分:0)

#include<stdio.h>

void partitionEqualAvt(int *a, int n)
{

    int i;
    int sum=0, sSum=0, eSum, sAvg, eAvg;
    for(i=0; i<n; i++)
        sum+=a[i];
    eSum=sum;
    for(i=0; i<n-1; i++)
    {
        sAvg=0;
        eAvg=0;
        sSum+=a[i];
        eSum=sum-sSum;
        sAvg=sSum/(i+1);
        eAvg=eSum/(n-i-1);
        if(sAvg == eAvg)
        {
            printf("\nAverage = %d from [%d to %d] and [%d to %d]", sAvg, 0, i, i+1, n);
        }
    }
}

int main()
{

    int a[]={1,1,1,1,1,1};
    int n=sizeof(a)/sizeof(int);
    partitionEqualAvt(a,n);
    return 0;
}

答案 5 :(得分:0)

使用贪心算法 模仿儿童为游戏选择团队的方式的问题的一种方法是贪婪算法,其以降序迭代数字,将它们中的每一个分配给具有较小总和的任何子集。当集合中的数字与其基数大小相同或更小时,这种方法很有效。

在python中试试这个: 如果平均值存在,那么可能找到它,否则它会让你接近平均值。

    a = [500, 1, -45, 46, -20, 100, -30, 4, 110]

    b, c = [], []

    m1, m2, n1, n2 = 0, 0, 0, 0
    count = 0
    for i in a:
        if count == 0:
            b.append(i)
            n1 += 1
            m1 = i
            n1 = 1
            count = 1
            continue
        else:
            tmp_m1 = (m1 * n1 + i) / (n1 + 1)
            tmp_m2 = (m2 * n2 + i) / (n2 + 1)
            print b, c, tmp_m1, tmp_m2
            if m1 > m2:
                if(tmp_m1 - m2 < m1 - tmp_m2):
                    b.append(i)
                    m1 = tmp_m1
                    n1 += 1
                else:
                    c.append(i)
                    m2 = tmp_m2
                    n2 += 1
            else:
                if(tmp_m1 - m2 < m1 - tmp_m2):
                    c.append(i)
                    m2 = tmp_m2
                    n2 += 1
                else:
                    c.append(i)
                    m1 = tmp_m1
                    n1 += 1
    print b, c, m1, m2

Sample output:
[500] [] 250 1
[500, 1] [] 151 -45
[500, 1, -45] [] 124 46
[500, 1, -45] [46] 108 13
[500, 1, -45, -20] [46] 106 73
[500, 1, -45, -20] [46, 100] 80 38
[500, 1, -45, -20, -30] [46, 100] 67 50
[500, 1, -45, -20, -30, 4] [46, 100] 73 85
[500, 1, -45, -20, -30, 4] [46, 100, 110] 73 73